aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorJoonas Lahtinen <joonas.lahtinen@linux.intel.com>2019-02-20 11:04:08 +0200
committerJoonas Lahtinen <joonas.lahtinen@linux.intel.com>2019-02-20 11:04:08 +0200
commitd0781a89c06f46d0f75e4e142061b8accb67cbe5 (patch)
tree6a1731bfc76fd92aac1880c23f75377462e07b35 /drivers/gpu/drm
parentdrm/i915: Use time based guilty context banning (diff)
parentMerge https://gitlab.freedesktop.org/drm/msm into drm-next (diff)
downloadlinux-dev-d0781a89c06f46d0f75e4e142061b8accb67cbe5.tar.xz
linux-dev-d0781a89c06f46d0f75e4e142061b8accb67cbe5.zip
Merge drm/drm-next into drm-intel-next-queued
Doing a backmerge to be able to merge topic/mei-hdcp-2019-02-19 PR. Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/Makefile4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c84
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c137
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c40
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c37
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c379
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c59
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c150
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c103
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c54
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c6844
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.h349
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_smc.c279
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_dpm.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_ih.c36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ih.c40
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_virtual.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c73
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_ih.c36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c22
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v10_0.c90
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0.c103
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v3_1.c72
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si.c54
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dma.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_ih.c38
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc15.c173
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ih.c60
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v4_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega10_ih.c324
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.c69
-rw-r--r--drivers/gpu/drm/amd/amdkfd/Kconfig4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.c8
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_module.c31
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h22
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c21
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c1471
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c48
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c71
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c17
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c89
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c59
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile5
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c96
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table.c135
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.c82
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c45
-rw-r--r--drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c256
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c159
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c162
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c90
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c82
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c69
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_surface.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c123
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_bios_types.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_helper.c36
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h60
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_abm.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.c647
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.h30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c133
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h35
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c224
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c129
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c205
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c84
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c107
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c42
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c203
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h37
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c237
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c36
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c201
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c74
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_pp_smu.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_services_types.h14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h107
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/Makefile99
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c606
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h86
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c106
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c505
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h78
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c574
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h218
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c160
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c329
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h54
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c129
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h32
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c120
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c875
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h54
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c173
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c284
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c120
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h32
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c97
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h32
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/engine.h111
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c118
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h115
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c284
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h77
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c251
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h80
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c601
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h81
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c491
-rw-r--r--drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h122
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/clock_source.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_status.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h17
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h19
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h20
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h (renamed from drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c)45
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/vm_helper.h (renamed from drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h)39
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq_types.h8
-rw-r--r--drivers/gpu/drm/amd/display/include/bios_parser_types.h4
-rw-r--r--drivers/gpu/drm/amd/display/include/gpio_interface.h8
-rw-r--r--drivers/gpu/drm/amd/display/include/i2caux_interface.h33
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.c165
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c106
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h2
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_shared.h3
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.c607
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_offset.h2
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_sh_mask.h4
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_smn.h58
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_0_smn.h54
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_0_smn.h53
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_offset.h2
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_sh_mask.h3
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h3
-rw-r--r--drivers/gpu/drm/amd/include/atombios.h2
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h53
-rw-r--r--drivers/gpu/drm/amd/include/kgd_pp_interface.h21
-rw-r--r--drivers/gpu/drm/amd/powerplay/amd_powerplay.c96
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/Makefile2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c101
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h (renamed from drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h)39
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c9
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c34
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c14
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c1
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c8
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c136
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.h (renamed from drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h)22
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c208
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h24
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c72
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c37
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c219
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c81
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.h (renamed from drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h)18
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c451
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h14
-rw-r--r--drivers/gpu/drm/arc/arcpgu_crtc.c2
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c6
-rw-r--r--drivers/gpu/drm/arc/arcpgu_sim.c3
-rw-r--r--drivers/gpu/drm/arm/Kconfig12
-rw-r--r--drivers/gpu/drm/arm/Makefile1
-rw-r--r--drivers/gpu/drm/arm/display/Kbuild3
-rw-r--r--drivers/gpu/drm/arm/display/Kconfig14
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_io.h42
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_product.h23
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_utils.h16
-rw-r--r--drivers/gpu/drm/arm/display/komeda/Makefile21
-rw-r--r--drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c111
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c110
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.c190
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.h110
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_drv.c144
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c75
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h89
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c167
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h34
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.c171
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.h114
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c202
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h359
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_plane.c109
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c88
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c4
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c6
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c2
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c2
-rw-r--r--drivers/gpu/drm/arm/malidp_mw.c2
-rw-r--r--drivers/gpu/drm/armada/armada_510.c2
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c2
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h2
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c2
-rw-r--r--drivers/gpu/drm/armada/armada_fb.c2
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c1
-rw-r--r--drivers/gpu/drm/ast/ast_main.c6
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c1
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c181
-rw-r--r--drivers/gpu/drm/bochs/bochs_drv.c1
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c1
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c3
-rw-r--r--drivers/gpu/drm/bridge/Kconfig1
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h4
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c1
-rw-r--r--drivers/gpu/drm/bridge/analogix-anx78xx.c2
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c2
-rw-r--r--drivers/gpu/drm/bridge/cdns-dsi.c542
-rw-r--r--drivers/gpu/drm/bridge/dumb-vga-dac.c2
-rw-r--r--drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c2
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c2
-rw-r--r--drivers/gpu/drm/bridge/panel.c2
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c2
-rw-r--r--drivers/gpu/drm/bridge/sii902x.c2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c144
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.h1
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c2
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c2
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c50
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c2
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c1
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c71
-rw-r--r--drivers/gpu/drm/drm_agpsupport.c2
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c19
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c7
-rw-r--r--drivers/gpu/drm/drm_bufs.c4
-rw-r--r--drivers/gpu/drm/drm_connector.c4
-rw-r--r--drivers/gpu/drm/drm_damage_helper.c1
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c47
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c150
-rw-r--r--drivers/gpu/drm/drm_dsc.c30
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c139
-rw-r--r--drivers/gpu/drm/drm_file.c2
-rw-r--r--drivers/gpu/drm/drm_fourcc.c9
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c2
-rw-r--r--drivers/gpu/drm/drm_gem.c2
-rw-r--r--drivers/gpu/drm/drm_irq.c10
-rw-r--r--drivers/gpu/drm/drm_lease.c3
-rw-r--r--drivers/gpu/drm/drm_mm.c2
-rw-r--r--drivers/gpu/drm/drm_modes.c4
-rw-r--r--drivers/gpu/drm/drm_modeset_helper.c4
-rw-r--r--drivers/gpu/drm/drm_pci.c5
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c2
-rw-r--r--drivers/gpu/drm/drm_property.c2
-rw-r--r--drivers/gpu/drm/drm_rect.c108
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c2
-rw-r--r--drivers/gpu/drm/drm_vblank.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h1
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c23
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_scaler.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c4
-rw-r--r--drivers/gpu/drm/exynos/regs-scaler.h2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c4
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c2
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c1
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h1
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c5
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c13
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c8
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c6
-rw-r--r--drivers/gpu/drm/i2c/ch7006_priv.h1
-rw-r--r--drivers/gpu/drm/i2c/sil164_drv.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c1
-rw-r--r--drivers/gpu/drm/i915/gvt/hypercall.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c30
-rw-r--r--drivers/gpu/drm/i915/gvt/mpt.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.c75
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.h1
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c3
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c2
-rw-r--r--drivers/gpu/drm/i915/i915_ioc32.c1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c2
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c2
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h2
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c2
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c2
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c25
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c2
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c19
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c2
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c2
-rw-r--r--drivers/gpu/drm/i915/intel_lpe_audio.c1
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c7
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c2
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c6
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c27
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c12
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c4
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_fb.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c2
-rw-r--r--drivers/gpu/drm/meson/meson_crtc.c25
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c24
-rw-r--r--drivers/gpu/drm/meson/meson_dw_hdmi.c27
-rw-r--r--drivers/gpu/drm/meson/meson_venc.c2
-rw-r--r--drivers/gpu/drm/meson/meson_venc_cvbs.c4
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c8
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c1
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c1
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h2
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c34
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h3
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c37
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h14
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h19
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h220
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c44
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h44
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h7
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h1
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c65
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c36
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c77
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h27
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c325
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h28
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h28
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c129
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h18
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c8
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c5
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h3
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c7
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c5
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_out.c2
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig12
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c214
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.c216
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h5
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.c1
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/atom.h6
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/core.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/curs.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c46
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/head.c1
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wimm.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.c2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/class.h13
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/clb069.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if000c.h30
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/ifc00d.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/vmm.h4
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/device.h3
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h3
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h3
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h4
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h14
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.h12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c307
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.c887
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.h60
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c248
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c46
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c835
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.h48
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vmm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vmm.h1
-rw-r--r--drivers/gpu/drm/nouveau/nv84_fence.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvif/disp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvif/vmm.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/subdev.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c)6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c95
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/user.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c)20
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c)14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c)14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/falcon.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c)10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c)30
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c)10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c331
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c23
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c (renamed from drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h)21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/base.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c)30
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c)14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c)39
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c106
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c)10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp100.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gv100.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c)8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c83
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c382
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h82
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk104.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk20a.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm200.c22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm20b.c14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c210
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp10b.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgv100.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmmcp77.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv04.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv41.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c (renamed from drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c)13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c60
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c27
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig21
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c473
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c54
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7701.c426
-rw-r--r--drivers/gpu/drm/pl111/pl111_drv.c8
-rw-r--r--drivers/gpu/drm/qxl/Makefile2
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c34
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c335
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c241
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c10
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h64
-rw-r--r--drivers/gpu/drm/qxl/qxl_dumb.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c300
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c83
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c12
-rw-r--r--drivers/gpu/drm/qxl/qxl_prime.c37
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c20
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/ci_dpm.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_acpi.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_dp_mst.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c1
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c5
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c38
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.h3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c56
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vsp.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.c98
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.h27
-rw-r--r--drivers/gpu/drm/rockchip/analogix_dp-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.c2
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.h2
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-reg.c2
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_psr.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c6
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_lvds.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_rgb.c17
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_rgb.h11
-rw-r--r--drivers/gpu/drm/savage/savage_state.c4
-rw-r--r--drivers/gpu/drm/scheduler/sched_entity.c7
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c219
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_crtc.c1
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_drv.c3
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_kms.c1
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c2
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c2
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c2
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c2
-rw-r--r--drivers/gpu/drm/stm/drv.c8
-rw-r--r--drivers/gpu/drm/stm/ltdc.c11
-rw-r--r--drivers/gpu/drm/sun4i/Kconfig3
-rw-r--r--drivers/gpu/drm/sun4i/Makefile5
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_crtc.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c6
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_frontend.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c6
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c37
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_lvds.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c5
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tv.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_drc.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c292
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c34
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h17
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c2
-rw-r--r--drivers/gpu/drm/tegra/Makefile1
-rw-r--r--drivers/gpu/drm/tegra/drm.c57
-rw-r--r--drivers/gpu/drm/tegra/drm.h5
-rw-r--r--drivers/gpu/drm/tegra/fb.c2
-rw-r--r--drivers/gpu/drm/tegra/hda.c63
-rw-r--r--drivers/gpu/drm/tegra/hda.h20
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c219
-rw-r--r--drivers/gpu/drm/tegra/hub.c2
-rw-r--r--drivers/gpu/drm/tegra/output.c11
-rw-r--r--drivers/gpu/drm/tegra/sor.c64
-rw-r--r--drivers/gpu/drm/tegra/vic.c75
-rw-r--r--drivers/gpu/drm/tegra/vic.h9
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c3
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-core.c2
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c20
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c19
-rw-r--r--drivers/gpu/drm/tve200/tve200_drv.c10
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c1
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c1
-rw-r--r--drivers/gpu/drm/udl/udl_main.c1
-rw-r--r--drivers/gpu/drm/v3d/v3d_sched.c13
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_dsi.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_perfmon.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_txp.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_vec.c2
-rw-r--r--drivers/gpu/drm/via/via_dmablit.c4
-rw-r--r--drivers/gpu/drm/via/via_drv.c3
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.c4
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h6
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_object.c13
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_prime.c14
-rw-r--r--drivers/gpu/drm/vkms/vkms_crc.c3
-rw-r--r--drivers/gpu/drm/vkms/vkms_crtc.c34
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c9
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.h2
-rw-r--r--drivers/gpu/drm/vkms/vkms_gem.c8
-rw-r--r--drivers/gpu/drm/vkms/vkms_output.c10
-rw-r--r--drivers/gpu/drm/vkms/vkms_plane.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c83
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mob.c21
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_validation.c6
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front.c2
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_conn.c2
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_gem.c15
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_kms.c4
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c2
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi.c2
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc.c2
-rw-r--r--drivers/gpu/drm/zte/zx_vga.c2
-rw-r--r--drivers/gpu/drm/zte/zx_vou.c2
779 files changed, 17829 insertions, 23868 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ce8d1d384319..1ac55c65eac0 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -51,7 +51,7 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
-obj-$(CONFIG_DRM_ARM) += arm/
+obj-y += arm/
obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_SCHED) += scheduler/
obj-$(CONFIG_DRM_TDFX) += tdfx/
@@ -81,7 +81,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_ARMADA) += armada/
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
-obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
+obj-y += rcar-du/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-y += omapdrm/
obj-$(CONFIG_DRM_SUN4I) += sun4i/
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index f76bcb9c45e4..466da5954a68 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -57,7 +57,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
# add asic specific block
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
- ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o
+ dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o
amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index bcef6ea4bcf9..9efa681d0878 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -542,6 +542,11 @@ struct amdgpu_asic_funcs {
bool (*need_full_reset)(struct amdgpu_device *adev);
/* initialize doorbell layout for specific asic*/
void (*init_doorbell_index)(struct amdgpu_device *adev);
+ /* PCIe bandwidth usage */
+ void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t *count0,
+ uint64_t *count1);
+ /* do we need to reset the asic at init time (e.g., kexec) */
+ bool (*need_reset_on_init)(struct amdgpu_device *adev);
};
/*
@@ -634,7 +639,7 @@ struct amdgpu_nbio_funcs {
void (*hdp_flush)(struct amdgpu_device *adev, struct amdgpu_ring *ring);
u32 (*get_memsize)(struct amdgpu_device *adev);
void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance,
- bool use_doorbell, int doorbell_index);
+ bool use_doorbell, int doorbell_index, int doorbell_size);
void (*enable_doorbell_aperture)(struct amdgpu_device *adev,
bool enable);
void (*enable_doorbell_selfring_aperture)(struct amdgpu_device *adev,
@@ -1042,6 +1047,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
#define amdgpu_asic_invalidate_hdp(adev, r) (adev)->asic_funcs->invalidate_hdp((adev), (r))
#define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev))
#define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev))
+#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
+#define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev))
/* Common functions */
bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 2dfaf158ef07..e957e42c539a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -28,8 +28,6 @@
#include <linux/module.h>
#include <linux/dma-buf.h>
-const struct kgd2kfd_calls *kgd2kfd;
-
static const unsigned int compute_vmid_bitmap = 0xFF00;
/* Total memory size in system memory and all GPU VRAM. Used to
@@ -47,12 +45,9 @@ int amdgpu_amdkfd_init(void)
amdgpu_amdkfd_total_mem_size *= si.mem_unit;
#ifdef CONFIG_HSA_AMD
- ret = kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd);
- if (ret)
- kgd2kfd = NULL;
+ ret = kgd2kfd_init();
amdgpu_amdkfd_gpuvm_init_mem_limits();
#else
- kgd2kfd = NULL;
ret = -ENOENT;
#endif
@@ -61,17 +56,13 @@ int amdgpu_amdkfd_init(void)
void amdgpu_amdkfd_fini(void)
{
- if (kgd2kfd)
- kgd2kfd->exit();
+ kgd2kfd_exit();
}
void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
{
const struct kfd2kgd_calls *kfd2kgd;
- if (!kgd2kfd)
- return;
-
switch (adev->asic_type) {
#ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_KAVERI:
@@ -98,8 +89,8 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
return;
}
- adev->kfd.dev = kgd2kfd->probe((struct kgd_dev *)adev,
- adev->pdev, kfd2kgd);
+ adev->kfd.dev = kgd2kfd_probe((struct kgd_dev *)adev,
+ adev->pdev, kfd2kgd);
if (adev->kfd.dev)
amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size;
@@ -182,7 +173,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
&gpu_resources.doorbell_start_offset);
if (adev->asic_type < CHIP_VEGA10) {
- kgd2kfd->device_init(adev->kfd.dev, &gpu_resources);
+ kgd2kfd_device_init(adev->kfd.dev, &gpu_resources);
return;
}
@@ -197,13 +188,13 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
* can use each doorbell assignment twice.
*/
gpu_resources.sdma_doorbell[0][i] =
- adev->doorbell_index.sdma_engine0 + (i >> 1);
+ adev->doorbell_index.sdma_engine[0] + (i >> 1);
gpu_resources.sdma_doorbell[0][i+1] =
- adev->doorbell_index.sdma_engine0 + 0x200 + (i >> 1);
+ adev->doorbell_index.sdma_engine[0] + 0x200 + (i >> 1);
gpu_resources.sdma_doorbell[1][i] =
- adev->doorbell_index.sdma_engine1 + (i >> 1);
+ adev->doorbell_index.sdma_engine[1] + (i >> 1);
gpu_resources.sdma_doorbell[1][i+1] =
- adev->doorbell_index.sdma_engine1 + 0x200 + (i >> 1);
+ adev->doorbell_index.sdma_engine[1] + 0x200 + (i >> 1);
}
/* Doorbells 0x0e0-0ff and 0x2e0-2ff are reserved for
* SDMA, IH and VCN. So don't use them for the CP.
@@ -211,14 +202,14 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
gpu_resources.reserved_doorbell_mask = 0x1e0;
gpu_resources.reserved_doorbell_val = 0x0e0;
- kgd2kfd->device_init(adev->kfd.dev, &gpu_resources);
+ kgd2kfd_device_init(adev->kfd.dev, &gpu_resources);
}
}
void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev)
{
if (adev->kfd.dev) {
- kgd2kfd->device_exit(adev->kfd.dev);
+ kgd2kfd_device_exit(adev->kfd.dev);
adev->kfd.dev = NULL;
}
}
@@ -227,13 +218,13 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,
const void *ih_ring_entry)
{
if (adev->kfd.dev)
- kgd2kfd->interrupt(adev->kfd.dev, ih_ring_entry);
+ kgd2kfd_interrupt(adev->kfd.dev, ih_ring_entry);
}
void amdgpu_amdkfd_suspend(struct amdgpu_device *adev)
{
if (adev->kfd.dev)
- kgd2kfd->suspend(adev->kfd.dev);
+ kgd2kfd_suspend(adev->kfd.dev);
}
int amdgpu_amdkfd_resume(struct amdgpu_device *adev)
@@ -241,7 +232,7 @@ int amdgpu_amdkfd_resume(struct amdgpu_device *adev)
int r = 0;
if (adev->kfd.dev)
- r = kgd2kfd->resume(adev->kfd.dev);
+ r = kgd2kfd_resume(adev->kfd.dev);
return r;
}
@@ -251,7 +242,7 @@ int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev)
int r = 0;
if (adev->kfd.dev)
- r = kgd2kfd->pre_reset(adev->kfd.dev);
+ r = kgd2kfd_pre_reset(adev->kfd.dev);
return r;
}
@@ -261,7 +252,7 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev)
int r = 0;
if (adev->kfd.dev)
- r = kgd2kfd->post_reset(adev->kfd.dev);
+ r = kgd2kfd_post_reset(adev->kfd.dev);
return r;
}
@@ -619,4 +610,47 @@ struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void)
{
return NULL;
}
+
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev,
+ const struct kfd2kgd_calls *f2g)
+{
+ return NULL;
+}
+
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
+ const struct kgd2kfd_shared_resources *gpu_resources)
+{
+ return false;
+}
+
+void kgd2kfd_device_exit(struct kfd_dev *kfd)
+{
+}
+
+void kgd2kfd_exit(void)
+{
+}
+
+void kgd2kfd_suspend(struct kfd_dev *kfd)
+{
+}
+
+int kgd2kfd_resume(struct kfd_dev *kfd)
+{
+ return 0;
+}
+
+int kgd2kfd_pre_reset(struct kfd_dev *kfd)
+{
+ return 0;
+}
+
+int kgd2kfd_post_reset(struct kfd_dev *kfd)
+{
+ return 0;
+}
+
+void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
+{
+}
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 70429f7aa9a8..0b31a1859023 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -33,7 +33,6 @@
#include "amdgpu_sync.h"
#include "amdgpu_vm.h"
-extern const struct kgd2kfd_calls *kgd2kfd;
extern uint64_t amdgpu_amdkfd_total_mem_size;
struct amdgpu_device;
@@ -214,4 +213,22 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd,
void amdgpu_amdkfd_gpuvm_init_mem_limits(void);
void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo);
+/* KGD2KFD callbacks */
+int kgd2kfd_init(void);
+void kgd2kfd_exit(void);
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev,
+ const struct kfd2kgd_calls *f2g);
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
+ const struct kgd2kfd_shared_resources *gpu_resources);
+void kgd2kfd_device_exit(struct kfd_dev *kfd);
+void kgd2kfd_suspend(struct kfd_dev *kfd);
+int kgd2kfd_resume(struct kfd_dev *kfd);
+int kgd2kfd_pre_reset(struct kfd_dev *kfd);
+int kgd2kfd_post_reset(struct kfd_dev *kfd);
+void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
+int kgd2kfd_quiesce_mm(struct mm_struct *mm);
+int kgd2kfd_resume_mm(struct mm_struct *mm);
+int kgd2kfd_schedule_evict_and_restore_process(struct mm_struct *mm,
+ struct dma_fence *fence);
+
#endif /* AMDGPU_AMDKFD_H_INCLUDED */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
index 574c1181ae9a..3107b9575929 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
@@ -122,7 +122,7 @@ static bool amdkfd_fence_enable_signaling(struct dma_fence *f)
if (dma_fence_is_signaled(f))
return true;
- if (!kgd2kfd->schedule_evict_and_restore_process(fence->mm, f))
+ if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f))
return true;
return false;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index be1ab43473c6..d7b10d79f1de 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1790,7 +1790,7 @@ int amdgpu_amdkfd_evict_userptr(struct kgd_mem *mem,
evicted_bos = atomic_inc_return(&process_info->evicted_bos);
if (evicted_bos == 1) {
/* First eviction, stop the queues */
- r = kgd2kfd->quiesce_mm(mm);
+ r = kgd2kfd_quiesce_mm(mm);
if (r)
pr_err("Failed to quiesce KFD\n");
schedule_delayed_work(&process_info->restore_userptr_work,
@@ -2082,7 +2082,7 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work)
evicted_bos)
goto unlock_out;
evicted_bos = 0;
- if (kgd2kfd->resume_mm(mm)) {
+ if (kgd2kfd_resume_mm(mm)) {
pr_err("%s: Failed to resume KFD\n", __func__);
/* No recovery from this failure. Probably the CP is
* hanging. No point trying again.
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
index a028661d9e20..92b11de19581 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -576,6 +576,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
{ 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX },
+ { 0x1002, 0x6900, 0x17AA, 0x3806, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0, 0, 0, 0, 0 },
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 69ad6ec0a4f3..bf04c12bd324 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -25,8 +25,8 @@
*/
#include <drm/drmP.h>
#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
#include "atom.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 1c49b8266d69..52a5e4fdc95b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -214,6 +214,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs
case AMDGPU_CHUNK_ID_DEPENDENCIES:
case AMDGPU_CHUNK_ID_SYNCOBJ_IN:
case AMDGPU_CHUNK_ID_SYNCOBJ_OUT:
+ case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES:
break;
default:
@@ -1090,6 +1091,15 @@ static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p,
fence = amdgpu_ctx_get_fence(ctx, entity,
deps[i].handle);
+
+ if (chunk->chunk_id == AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES) {
+ struct drm_sched_fence *s_fence = to_drm_sched_fence(fence);
+ struct dma_fence *old = fence;
+
+ fence = dma_fence_get(&s_fence->scheduled);
+ dma_fence_put(old);
+ }
+
if (IS_ERR(fence)) {
r = PTR_ERR(fence);
amdgpu_ctx_put(ctx);
@@ -1177,7 +1187,8 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
chunk = &p->chunks[i];
- if (chunk->chunk_id == AMDGPU_CHUNK_ID_DEPENDENCIES) {
+ if (chunk->chunk_id == AMDGPU_CHUNK_ID_DEPENDENCIES ||
+ chunk->chunk_id == AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES) {
r = amdgpu_cs_process_fence_dep(p, chunk);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 28bccceaa363..4f8fb4ecde34 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -30,8 +30,8 @@
#include <linux/console.h>
#include <linux/slab.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
@@ -1645,7 +1645,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
if (r) {
DRM_ERROR("sw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
- return r;
+ goto init_failed;
}
adev->ip_blocks[i].status.sw = true;
@@ -1654,17 +1654,17 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
r = amdgpu_device_vram_scratch_init(adev);
if (r) {
DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r);
- return r;
+ goto init_failed;
}
r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev);
if (r) {
DRM_ERROR("hw_init %d failed %d\n", i, r);
- return r;
+ goto init_failed;
}
r = amdgpu_device_wb_init(adev);
if (r) {
DRM_ERROR("amdgpu_device_wb_init failed %d\n", r);
- return r;
+ goto init_failed;
}
adev->ip_blocks[i].status.hw = true;
@@ -1675,7 +1675,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
AMDGPU_CSA_SIZE);
if (r) {
DRM_ERROR("allocate CSA failed %d\n", r);
- return r;
+ goto init_failed;
}
}
}
@@ -1683,28 +1683,32 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
r = amdgpu_ucode_create_bo(adev); /* create ucode bo when sw_init complete*/
if (r)
- return r;
+ goto init_failed;
r = amdgpu_device_ip_hw_init_phase1(adev);
if (r)
- return r;
+ goto init_failed;
r = amdgpu_device_fw_loading(adev);
if (r)
- return r;
+ goto init_failed;
r = amdgpu_device_ip_hw_init_phase2(adev);
if (r)
- return r;
+ goto init_failed;
if (adev->gmc.xgmi.num_physical_nodes > 1)
amdgpu_xgmi_add_device(adev);
amdgpu_amdkfd_device_init(adev);
- if (amdgpu_sriov_vf(adev))
+init_failed:
+ if (amdgpu_sriov_vf(adev)) {
+ if (!r)
+ amdgpu_virt_init_data_exchange(adev);
amdgpu_virt_release_full_gpu(adev, true);
+ }
- return 0;
+ return r;
}
/**
@@ -2131,7 +2135,7 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
continue;
r = block->version->funcs->hw_init(adev);
- DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
+ DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
if (r)
return r;
}
@@ -2165,7 +2169,7 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev)
continue;
r = block->version->funcs->hw_init(adev);
- DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
+ DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
if (r)
return r;
}
@@ -2546,6 +2550,17 @@ int amdgpu_device_init(struct amdgpu_device *adev,
/* detect if we are with an SRIOV vbios */
amdgpu_device_detect_sriov_bios(adev);
+ /* check if we need to reset the asic
+ * E.g., driver was not cleanly unloaded previously, etc.
+ */
+ if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) {
+ r = amdgpu_asic_reset(adev);
+ if (r) {
+ dev_err(adev->dev, "asic reset on init failed\n");
+ goto failed;
+ }
+ }
+
/* Post card if necessary */
if (amdgpu_device_need_post(adev)) {
if (!adev->bios) {
@@ -2610,6 +2625,8 @@ fence_driver_init:
}
dev_err(adev->dev, "amdgpu_device_ip_init failed\n");
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0);
+ if (amdgpu_virt_request_full_gpu(adev, false))
+ amdgpu_virt_release_full_gpu(adev, false);
goto failed;
}
@@ -2632,9 +2649,6 @@ fence_driver_init:
goto failed;
}
- if (amdgpu_sriov_vf(adev))
- amdgpu_virt_init_data_exchange(adev);
-
amdgpu_fbdev_init(adev);
r = amdgpu_pm_sysfs_init(adev);
@@ -2798,7 +2812,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
struct drm_framebuffer *fb = crtc->primary->fb;
struct amdgpu_bo *robj;
- if (amdgpu_crtc->cursor_bo) {
+ if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) {
struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo);
r = amdgpu_bo_reserve(aobj, true);
if (r == 0) {
@@ -2906,7 +2920,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- if (amdgpu_crtc->cursor_bo) {
+ if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) {
struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo);
r = amdgpu_bo_reserve(aobj, true);
if (r == 0) {
@@ -3226,6 +3240,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
r = amdgpu_ib_ring_tests(adev);
error:
+ amdgpu_virt_init_data_exchange(adev);
amdgpu_virt_release_full_gpu(adev, true);
if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) {
atomic_inc(&adev->vram_lost_counter);
@@ -3298,17 +3313,15 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
if (!ring || !ring->sched.thread)
continue;
- kthread_park(ring->sched.thread);
-
- if (job && job->base.sched != &ring->sched)
- continue;
-
- drm_sched_hw_job_reset(&ring->sched, job ? &job->base : NULL);
+ drm_sched_stop(&ring->sched);
/* after all hw jobs are reset, hw fence is meaningless, so force_completion */
amdgpu_fence_driver_force_completion(ring);
}
+ if(job)
+ drm_sched_increase_karma(&job->base);
+
if (!amdgpu_sriov_vf(adev)) {
@@ -3454,14 +3467,10 @@ static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev,
if (!ring || !ring->sched.thread)
continue;
- /* only need recovery sched of the given job's ring
- * or all rings (in the case @job is NULL)
- * after above amdgpu_reset accomplished
- */
- if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res)
- drm_sched_job_recovery(&ring->sched);
+ if (!adev->asic_reset_res)
+ drm_sched_resubmit_jobs(&ring->sched);
- kthread_unpark(ring->sched.thread);
+ drm_sched_start(&ring->sched, !adev->asic_reset_res);
}
if (!amdgpu_device_has_dc_support(adev)) {
@@ -3521,9 +3530,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
* by different nodes. No point also since the one node already executing
* reset will also reset all the other nodes in the hive.
*/
- hive = amdgpu_get_xgmi_hive(adev);
+ hive = amdgpu_get_xgmi_hive(adev, 0);
if (hive && adev->gmc.xgmi.num_physical_nodes > 1 &&
- !mutex_trylock(&hive->hive_lock))
+ !mutex_trylock(&hive->reset_lock))
return 0;
/* Start with adev pre asic reset first for soft reset check.*/
@@ -3602,13 +3611,45 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */
}
if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
- mutex_unlock(&hive->hive_lock);
+ mutex_unlock(&hive->reset_lock);
if (r)
dev_info(adev->dev, "GPU reset end with ret = %d\n", r);
return r;
}
+static void amdgpu_device_get_min_pci_speed_width(struct amdgpu_device *adev,
+ enum pci_bus_speed *speed,
+ enum pcie_link_width *width)
+{
+ struct pci_dev *pdev = adev->pdev;
+ enum pci_bus_speed cur_speed;
+ enum pcie_link_width cur_width;
+
+ *speed = PCI_SPEED_UNKNOWN;
+ *width = PCIE_LNK_WIDTH_UNKNOWN;
+
+ while (pdev) {
+ cur_speed = pcie_get_speed_cap(pdev);
+ cur_width = pcie_get_width_cap(pdev);
+
+ if (cur_speed != PCI_SPEED_UNKNOWN) {
+ if (*speed == PCI_SPEED_UNKNOWN)
+ *speed = cur_speed;
+ else if (cur_speed < *speed)
+ *speed = cur_speed;
+ }
+
+ if (cur_width != PCIE_LNK_WIDTH_UNKNOWN) {
+ if (*width == PCIE_LNK_WIDTH_UNKNOWN)
+ *width = cur_width;
+ else if (cur_width < *width)
+ *width = cur_width;
+ }
+ pdev = pci_upstream_bridge(pdev);
+ }
+}
+
/**
* amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot
*
@@ -3621,8 +3662,8 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */
static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
{
struct pci_dev *pdev;
- enum pci_bus_speed speed_cap;
- enum pcie_link_width link_width;
+ enum pci_bus_speed speed_cap, platform_speed_cap;
+ enum pcie_link_width platform_link_width;
if (amdgpu_pcie_gen_cap)
adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap;
@@ -3639,6 +3680,12 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
return;
}
+ if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask)
+ return;
+
+ amdgpu_device_get_min_pci_speed_width(adev, &platform_speed_cap,
+ &platform_link_width);
+
if (adev->pm.pcie_gen_mask == 0) {
/* asic caps */
pdev = adev->pdev;
@@ -3664,22 +3711,20 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
adev->pm.pcie_gen_mask |= CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1;
}
/* platform caps */
- pdev = adev->ddev->pdev->bus->self;
- speed_cap = pcie_get_speed_cap(pdev);
- if (speed_cap == PCI_SPEED_UNKNOWN) {
+ if (platform_speed_cap == PCI_SPEED_UNKNOWN) {
adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2);
} else {
- if (speed_cap == PCIE_SPEED_16_0GT)
+ if (platform_speed_cap == PCIE_SPEED_16_0GT)
adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4);
- else if (speed_cap == PCIE_SPEED_8_0GT)
+ else if (platform_speed_cap == PCIE_SPEED_8_0GT)
adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3);
- else if (speed_cap == PCIE_SPEED_5_0GT)
+ else if (platform_speed_cap == PCIE_SPEED_5_0GT)
adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2);
else
@@ -3688,12 +3733,10 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
}
}
if (adev->pm.pcie_mlw_mask == 0) {
- pdev = adev->ddev->pdev->bus->self;
- link_width = pcie_get_width_cap(pdev);
- if (link_width == PCIE_LNK_WIDTH_UNKNOWN) {
+ if (platform_link_width == PCIE_LNK_WIDTH_UNKNOWN) {
adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_PCIE_MLW_MASK;
} else {
- switch (link_width) {
+ switch (platform_link_width) {
case PCIE_LNK_X32:
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 15ce7e681d67..b083b219b1a9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -188,10 +188,12 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
goto cleanup;
}
- r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev));
- if (unlikely(r != 0)) {
- DRM_ERROR("failed to pin new abo buffer before flip\n");
- goto unreserve;
+ if (!adev->enable_virtual_display) {
+ r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev));
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to pin new abo buffer before flip\n");
+ goto unreserve;
+ }
}
r = amdgpu_ttm_alloc_gart(&new_abo->tbo);
@@ -211,7 +213,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
amdgpu_bo_get_tiling_flags(new_abo, &tiling_flags);
amdgpu_bo_unreserve(new_abo);
- work->base = amdgpu_bo_gpu_offset(new_abo);
+ if (!adev->enable_virtual_display)
+ work->base = amdgpu_bo_gpu_offset(new_abo);
work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
amdgpu_get_vblank_counter_kms(dev, work->crtc_id);
@@ -242,9 +245,10 @@ pflip_cleanup:
goto cleanup;
}
unpin:
- if (unlikely(amdgpu_bo_unpin(new_abo) != 0)) {
- DRM_ERROR("failed to unpin new abo in error path\n");
- }
+ if (!adev->enable_virtual_display)
+ if (unlikely(amdgpu_bo_unpin(new_abo) != 0))
+ DRM_ERROR("failed to unpin new abo in error path\n");
+
unreserve:
amdgpu_bo_unreserve(new_abo);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h
index be620b29f4aa..1cfec06f81d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h
@@ -51,14 +51,7 @@ struct amdgpu_doorbell_index {
uint32_t userqueue_start;
uint32_t userqueue_end;
uint32_t gfx_ring0;
- uint32_t sdma_engine0;
- uint32_t sdma_engine1;
- uint32_t sdma_engine2;
- uint32_t sdma_engine3;
- uint32_t sdma_engine4;
- uint32_t sdma_engine5;
- uint32_t sdma_engine6;
- uint32_t sdma_engine7;
+ uint32_t sdma_engine[8];
uint32_t ih;
union {
struct {
@@ -79,6 +72,8 @@ struct amdgpu_doorbell_index {
} uvd_vce;
};
uint32_t max_assignment;
+ /* Per engine SDMA doorbell size in dword */
+ uint32_t sdma_doorbell_range;
};
typedef enum _AMDGPU_DOORBELL_ASSIGNMENT
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
index f972cd156795..2f61e9edb1c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
@@ -364,6 +364,14 @@ enum amdgpu_pcie_gen {
((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\
(adev)->powerplay.pp_handle))
+#define amdgpu_dpm_get_ppfeature_status(adev, buf) \
+ ((adev)->powerplay.pp_funcs->get_ppfeature_status(\
+ (adev)->powerplay.pp_handle, (buf)))
+
+#define amdgpu_dpm_set_ppfeature_status(adev, ppfeatures) \
+ ((adev)->powerplay.pp_funcs->set_ppfeature_status(\
+ (adev)->powerplay.pp_handle, (ppfeatures)))
+
struct amdgpu_dpm {
struct amdgpu_ps *ps;
/* number of valid power states */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index c806f984bcc5..7f3aa7b7e1d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -32,7 +32,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/vga_switcheroo.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "amdgpu.h"
#include "amdgpu_irq.h"
@@ -71,9 +71,11 @@
* - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
* - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
* - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES
+ * - 3.29.0 - Add AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID
*/
#define KMS_DRIVER_MAJOR 3
-#define KMS_DRIVER_MINOR 27
+#define KMS_DRIVER_MINOR 29
#define KMS_DRIVER_PATCHLEVEL 0
int amdgpu_vram_limit = 0;
@@ -1189,7 +1191,7 @@ amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
static struct drm_driver kms_driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_ATOMIC |
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
+ DRIVER_GEM |
DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ,
.load = amdgpu_driver_load_kms,
.open = amdgpu_driver_open_kms,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
index ecbcefe49a98..f89f5734d985 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
@@ -37,6 +37,8 @@ struct amdgpu_gds {
struct amdgpu_gds_asic_info mem;
struct amdgpu_gds_asic_info gws;
struct amdgpu_gds_asic_info oa;
+ uint32_t gds_compute_max_wave_id;
+
/* At present, GDS, GWS and OA resources for gfx (graphics)
* is always pre-allocated and available for graphics operation.
* Such resource is shared between all gfx clients.
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index f4f00217546e..d21dd2f369da 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -54,10 +54,6 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
memset(&bp, 0, sizeof(bp));
*obj = NULL;
- /* At least align on page size */
- if (alignment < PAGE_SIZE) {
- alignment = PAGE_SIZE;
- }
bp.size = size;
bp.byte_align = alignment;
@@ -244,9 +240,6 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
- /* GDS allocations must be DW aligned */
- if (args->in.domains & AMDGPU_GEM_DOMAIN_GDS)
- size = ALIGN(size, 4);
}
if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index c48207b377bc..0b8ef2d27d6b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -202,12 +202,12 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
amdgpu_asic_flush_hdp(adev, ring);
}
+ if (need_ctx_switch)
+ status |= AMDGPU_HAVE_CTX_SWITCH;
+
skip_preamble = ring->current_ctx == fence_ctx;
if (job && ring->funcs->emit_cntxcntl) {
- if (need_ctx_switch)
- status |= AMDGPU_HAVE_CTX_SWITCH;
status |= job->preamble_status;
-
amdgpu_ring_emit_cntxcntl(ring, status);
}
@@ -221,8 +221,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
!amdgpu_sriov_vf(adev)) /* for SRIOV preemption, Preamble CE ib must be inserted anyway */
continue;
- amdgpu_ring_emit_ib(ring, job, ib, need_ctx_switch);
- need_ctx_switch = false;
+ amdgpu_ring_emit_ib(ring, job, ib, status);
+ status &= ~AMDGPU_HAVE_CTX_SWITCH;
}
if (ring->funcs->emit_tmz)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
index 8af67f649660..d0a5db777b6d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
@@ -52,6 +52,8 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
ih->use_bus_addr = use_bus_addr;
if (use_bus_addr) {
+ dma_addr_t dma_addr;
+
if (ih->ring)
return 0;
@@ -59,21 +61,26 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
* add them to the end of the ring allocation.
*/
ih->ring = dma_alloc_coherent(adev->dev, ih->ring_size + 8,
- &ih->rb_dma_addr, GFP_KERNEL);
+ &dma_addr, GFP_KERNEL);
if (ih->ring == NULL)
return -ENOMEM;
memset((void *)ih->ring, 0, ih->ring_size + 8);
- ih->wptr_offs = (ih->ring_size / 4) + 0;
- ih->rptr_offs = (ih->ring_size / 4) + 1;
+ ih->gpu_addr = dma_addr;
+ ih->wptr_addr = dma_addr + ih->ring_size;
+ ih->wptr_cpu = &ih->ring[ih->ring_size / 4];
+ ih->rptr_addr = dma_addr + ih->ring_size + 4;
+ ih->rptr_cpu = &ih->ring[(ih->ring_size / 4) + 1];
} else {
- r = amdgpu_device_wb_get(adev, &ih->wptr_offs);
+ unsigned wptr_offs, rptr_offs;
+
+ r = amdgpu_device_wb_get(adev, &wptr_offs);
if (r)
return r;
- r = amdgpu_device_wb_get(adev, &ih->rptr_offs);
+ r = amdgpu_device_wb_get(adev, &rptr_offs);
if (r) {
- amdgpu_device_wb_free(adev, ih->wptr_offs);
+ amdgpu_device_wb_free(adev, wptr_offs);
return r;
}
@@ -82,10 +89,15 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
&ih->ring_obj, &ih->gpu_addr,
(void **)&ih->ring);
if (r) {
- amdgpu_device_wb_free(adev, ih->rptr_offs);
- amdgpu_device_wb_free(adev, ih->wptr_offs);
+ amdgpu_device_wb_free(adev, rptr_offs);
+ amdgpu_device_wb_free(adev, wptr_offs);
return r;
}
+
+ ih->wptr_addr = adev->wb.gpu_addr + wptr_offs * 4;
+ ih->wptr_cpu = &adev->wb.wb[wptr_offs];
+ ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
+ ih->rptr_cpu = &adev->wb.wb[rptr_offs];
}
return 0;
}
@@ -109,13 +121,13 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
* add them to the end of the ring allocation.
*/
dma_free_coherent(adev->dev, ih->ring_size + 8,
- (void *)ih->ring, ih->rb_dma_addr);
+ (void *)ih->ring, ih->gpu_addr);
ih->ring = NULL;
} else {
amdgpu_bo_free_kernel(&ih->ring_obj, &ih->gpu_addr,
(void **)&ih->ring);
- amdgpu_device_wb_free(adev, ih->wptr_offs);
- amdgpu_device_wb_free(adev, ih->rptr_offs);
+ amdgpu_device_wb_free(adev, (ih->wptr_addr - ih->gpu_addr) / 4);
+ amdgpu_device_wb_free(adev, (ih->rptr_addr - ih->gpu_addr) / 4);
}
}
@@ -137,7 +149,7 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
if (!ih->enabled || adev->shutdown)
return IRQ_NONE;
- wptr = amdgpu_ih_get_wptr(adev);
+ wptr = amdgpu_ih_get_wptr(adev, ih);
restart_ih:
/* is somebody else already processing irqs? */
@@ -154,11 +166,11 @@ restart_ih:
ih->rptr &= ih->ptr_mask;
}
- amdgpu_ih_set_rptr(adev);
+ amdgpu_ih_set_rptr(adev, ih);
atomic_set(&ih->lock, 0);
/* make sure wptr hasn't changed while processing */
- wptr = amdgpu_ih_get_wptr(adev);
+ wptr = amdgpu_ih_get_wptr(adev, ih);
if (wptr != ih->rptr)
goto restart_ih;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
index f877bb78d10a..1ccb1831382a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
@@ -31,34 +31,40 @@ struct amdgpu_iv_entry;
* R6xx+ IH ring
*/
struct amdgpu_ih_ring {
- struct amdgpu_bo *ring_obj;
- volatile uint32_t *ring;
- unsigned rptr;
unsigned ring_size;
- uint64_t gpu_addr;
uint32_t ptr_mask;
- atomic_t lock;
- bool enabled;
- unsigned wptr_offs;
- unsigned rptr_offs;
u32 doorbell_index;
bool use_doorbell;
bool use_bus_addr;
- dma_addr_t rb_dma_addr; /* only used when use_bus_addr = true */
+
+ struct amdgpu_bo *ring_obj;
+ volatile uint32_t *ring;
+ uint64_t gpu_addr;
+
+ uint64_t wptr_addr;
+ volatile uint32_t *wptr_cpu;
+
+ uint64_t rptr_addr;
+ volatile uint32_t *rptr_cpu;
+
+ bool enabled;
+ unsigned rptr;
+ atomic_t lock;
};
/* provided by the ih block */
struct amdgpu_ih_funcs {
/* ring read/write ptr handling, called from interrupt context */
- u32 (*get_wptr)(struct amdgpu_device *adev);
- void (*decode_iv)(struct amdgpu_device *adev,
+ u32 (*get_wptr)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
+ void (*decode_iv)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
struct amdgpu_iv_entry *entry);
- void (*set_rptr)(struct amdgpu_device *adev);
+ void (*set_rptr)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
};
-#define amdgpu_ih_get_wptr(adev) (adev)->irq.ih_funcs->get_wptr((adev))
-#define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv))
-#define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev))
+#define amdgpu_ih_get_wptr(adev, ih) (adev)->irq.ih_funcs->get_wptr((adev), (ih))
+#define amdgpu_ih_decode_iv(adev, iv) \
+ (adev)->irq.ih_funcs->decode_iv((adev), (ih), (iv))
+#define amdgpu_ih_set_rptr(adev, ih) (adev)->irq.ih_funcs->set_rptr((adev), (ih))
int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
unsigned ring_size, bool use_bus_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index b7968f426862..8bfb3dab46f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -148,6 +148,8 @@ static void amdgpu_irq_callback(struct amdgpu_device *adev,
entry.iv_entry = (const uint32_t *)&ih->ring[ring_index];
amdgpu_ih_decode_iv(adev, &entry);
+ trace_amdgpu_iv(ih - &adev->irq.ih, &entry);
+
amdgpu_irq_dispatch(adev, &entry);
}
@@ -175,6 +177,36 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg)
}
/**
+ * amdgpu_irq_handle_ih1 - kick of processing for IH1
+ *
+ * @work: work structure in struct amdgpu_irq
+ *
+ * Kick of processing IH ring 1.
+ */
+static void amdgpu_irq_handle_ih1(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+ irq.ih1_work);
+
+ amdgpu_ih_process(adev, &adev->irq.ih1, amdgpu_irq_callback);
+}
+
+/**
+ * amdgpu_irq_handle_ih2 - kick of processing for IH2
+ *
+ * @work: work structure in struct amdgpu_irq
+ *
+ * Kick of processing IH ring 2.
+ */
+static void amdgpu_irq_handle_ih2(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+ irq.ih2_work);
+
+ amdgpu_ih_process(adev, &adev->irq.ih2, amdgpu_irq_callback);
+}
+
+/**
* amdgpu_msi_ok - check whether MSI functionality is enabled
*
* @adev: amdgpu device pointer (unused)
@@ -238,6 +270,9 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
amdgpu_hotplug_work_func);
}
+ INIT_WORK(&adev->irq.ih1_work, amdgpu_irq_handle_ih1);
+ INIT_WORK(&adev->irq.ih2_work, amdgpu_irq_handle_ih2);
+
adev->irq.installed = true;
r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
if (r) {
@@ -367,8 +402,6 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
bool handled = false;
int r;
- trace_amdgpu_iv(entry);
-
if (client_id >= AMDGPU_IRQ_CLIENTID_MAX) {
DRM_DEBUG("Invalid client_id in IV: %d\n", client_id);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
index f6ce171cb8aa..c27decfda494 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -87,9 +87,11 @@ struct amdgpu_irq {
/* status, etc. */
bool msi_enabled; /* msi enabled */
- /* interrupt ring */
- struct amdgpu_ih_ring ih;
- const struct amdgpu_ih_funcs *ih_funcs;
+ /* interrupt rings */
+ struct amdgpu_ih_ring ih, ih1, ih2;
+ const struct amdgpu_ih_funcs *ih_funcs;
+ struct work_struct ih1_work, ih2_work;
+ struct amdgpu_irq_src self_irq;
/* gen irq stuff */
struct irq_domain *domain; /* GPU irq controller domain */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index aadd0fa42e43..698fd8a2f775 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -38,6 +38,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/hrtimer.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 728e15e5d68a..fd9c4beeaaa4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -426,12 +426,20 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
size_t acc_size;
int r;
- page_align = roundup(bp->byte_align, PAGE_SIZE) >> PAGE_SHIFT;
- if (bp->domain & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS |
- AMDGPU_GEM_DOMAIN_OA))
+ /* Note that GDS/GWS/OA allocates 1 page per byte/resource. */
+ if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) {
+ /* GWS and OA don't need any alignment. */
+ page_align = bp->byte_align;
size <<= PAGE_SHIFT;
- else
+ } else if (bp->domain & AMDGPU_GEM_DOMAIN_GDS) {
+ /* Both size and alignment must be a multiple of 4. */
+ page_align = ALIGN(bp->byte_align, 4);
+ size = ALIGN(size, 4) << PAGE_SHIFT;
+ } else {
+ /* Memory should be aligned at least to a page size. */
+ page_align = ALIGN(bp->byte_align, PAGE_SIZE) >> PAGE_SHIFT;
size = ALIGN(size, PAGE_SIZE);
+ }
if (!amdgpu_bo_validate_size(adev, size, bp->domain))
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 1f61ed95727c..a7adb7b6bd98 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -626,11 +626,71 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
}
/**
- * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
+ * DOC: ppfeatures
+ *
+ * The amdgpu driver provides a sysfs API for adjusting what powerplay
+ * features to be enabled. The file ppfeatures is used for this. And
+ * this is only available for Vega10 and later dGPUs.
+ *
+ * Reading back the file will show you the followings:
+ * - Current ppfeature masks
+ * - List of the all supported powerplay features with their naming,
+ * bitmasks and enablement status('Y'/'N' means "enabled"/"disabled").
+ *
+ * To manually enable or disable a specific feature, just set or clear
+ * the corresponding bit from original ppfeature masks and input the
+ * new ppfeature masks.
+ */
+static ssize_t amdgpu_set_ppfeature_status(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ uint64_t featuremask;
+ int ret;
+
+ ret = kstrtou64(buf, 0, &featuremask);
+ if (ret)
+ return -EINVAL;
+
+ pr_debug("featuremask = 0x%llx\n", featuremask);
+
+ if (adev->powerplay.pp_funcs->set_ppfeature_status) {
+ ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask);
+ if (ret)
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t amdgpu_get_ppfeature_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+
+ if (adev->powerplay.pp_funcs->get_ppfeature_status)
+ return amdgpu_dpm_get_ppfeature_status(adev, buf);
+
+ return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+/**
+ * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk
+ * pp_dpm_pcie
*
* The amdgpu driver provides a sysfs API for adjusting what power levels
* are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk,
- * and pp_dpm_pcie are used for this.
+ * pp_dpm_socclk, pp_dpm_fclk, pp_dpm_dcefclk and pp_dpm_pcie are used for
+ * this.
+ *
+ * pp_dpm_socclk and pp_dpm_dcefclk interfaces are only available for
+ * Vega10 and later ASICs.
+ * pp_dpm_fclk interface is only available for Vega20 and later ASICs.
*
* Reading back the files will show you the available power levels within
* the power state and the clock information for those levels.
@@ -640,6 +700,8 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
* Secondly,Enter a new value for each level by inputing a string that
* contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie"
* E.g., echo 4 5 6 to > pp_dpm_sclk will enable sclk levels 4, 5, and 6.
+ *
+ * NOTE: change to the dcefclk max dpm level is not supported now
*/
static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
@@ -750,6 +812,114 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev,
return count;
}
+static ssize_t amdgpu_get_pp_dpm_socclk(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+
+ if (adev->powerplay.pp_funcs->print_clock_levels)
+ return amdgpu_dpm_print_clock_levels(adev, PP_SOCCLK, buf);
+ else
+ return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ int ret;
+ uint32_t mask = 0;
+
+ ret = amdgpu_read_mask(buf, count, &mask);
+ if (ret)
+ return ret;
+
+ if (adev->powerplay.pp_funcs->force_clock_level)
+ ret = amdgpu_dpm_force_clock_level(adev, PP_SOCCLK, mask);
+
+ if (ret)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t amdgpu_get_pp_dpm_fclk(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+
+ if (adev->powerplay.pp_funcs->print_clock_levels)
+ return amdgpu_dpm_print_clock_levels(adev, PP_FCLK, buf);
+ else
+ return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ int ret;
+ uint32_t mask = 0;
+
+ ret = amdgpu_read_mask(buf, count, &mask);
+ if (ret)
+ return ret;
+
+ if (adev->powerplay.pp_funcs->force_clock_level)
+ ret = amdgpu_dpm_force_clock_level(adev, PP_FCLK, mask);
+
+ if (ret)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+
+ if (adev->powerplay.pp_funcs->print_clock_levels)
+ return amdgpu_dpm_print_clock_levels(adev, PP_DCEFCLK, buf);
+ else
+ return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static ssize_t amdgpu_set_pp_dpm_dcefclk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ int ret;
+ uint32_t mask = 0;
+
+ ret = amdgpu_read_mask(buf, count, &mask);
+ if (ret)
+ return ret;
+
+ if (adev->powerplay.pp_funcs->force_clock_level)
+ ret = amdgpu_dpm_force_clock_level(adev, PP_DCEFCLK, mask);
+
+ if (ret)
+ return -EINVAL;
+
+ return count;
+}
+
static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -990,6 +1160,31 @@ static ssize_t amdgpu_get_busy_percent(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", value);
}
+/**
+ * DOC: pcie_bw
+ *
+ * The amdgpu driver provides a sysfs API for estimating how much data
+ * has been received and sent by the GPU in the last second through PCIe.
+ * The file pcie_bw is used for this.
+ * The Perf counters count the number of received and sent messages and return
+ * those values, as well as the maximum payload size of a PCIe packet (mps).
+ * Note that it is not possible to easily and quickly obtain the size of each
+ * packet transmitted, so we output the max payload size (mps) to allow for
+ * quick estimation of the PCIe bandwidth usage
+ */
+static ssize_t amdgpu_get_pcie_bw(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ uint64_t count0, count1;
+
+ amdgpu_asic_get_pcie_usage(adev, &count0, &count1);
+ return snprintf(buf, PAGE_SIZE, "%llu %llu %i\n",
+ count0, count1, pcie_get_mps(adev->pdev));
+}
+
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state);
static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
amdgpu_get_dpm_forced_performance_level,
@@ -1008,6 +1203,15 @@ static DEVICE_ATTR(pp_dpm_sclk, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR,
amdgpu_get_pp_dpm_mclk,
amdgpu_set_pp_dpm_mclk);
+static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR,
+ amdgpu_get_pp_dpm_socclk,
+ amdgpu_set_pp_dpm_socclk);
+static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR,
+ amdgpu_get_pp_dpm_fclk,
+ amdgpu_set_pp_dpm_fclk);
+static DEVICE_ATTR(pp_dpm_dcefclk, S_IRUGO | S_IWUSR,
+ amdgpu_get_pp_dpm_dcefclk,
+ amdgpu_set_pp_dpm_dcefclk);
static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR,
amdgpu_get_pp_dpm_pcie,
amdgpu_set_pp_dpm_pcie);
@@ -1025,6 +1229,10 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
amdgpu_set_pp_od_clk_voltage);
static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
amdgpu_get_busy_percent, NULL);
+static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL);
+static DEVICE_ATTR(ppfeatures, S_IRUGO | S_IWUSR,
+ amdgpu_get_ppfeature_status,
+ amdgpu_set_ppfeature_status);
static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
struct device_attribute *attr,
@@ -1516,6 +1724,75 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
return count;
}
+static ssize_t amdgpu_hwmon_show_sclk(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ struct drm_device *ddev = adev->ddev;
+ uint32_t sclk;
+ int r, size = sizeof(sclk);
+
+ /* Can't get voltage when the card is off */
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
+ /* sanity check PP is enabled */
+ if (!(adev->powerplay.pp_funcs &&
+ adev->powerplay.pp_funcs->read_sensor))
+ return -EINVAL;
+
+ /* get the sclk */
+ r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
+ (void *)&sclk, &size);
+ if (r)
+ return r;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", sclk * 10 * 1000);
+}
+
+static ssize_t amdgpu_hwmon_show_sclk_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "sclk\n");
+}
+
+static ssize_t amdgpu_hwmon_show_mclk(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ struct drm_device *ddev = adev->ddev;
+ uint32_t mclk;
+ int r, size = sizeof(mclk);
+
+ /* Can't get voltage when the card is off */
+ if ((adev->flags & AMD_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
+ /* sanity check PP is enabled */
+ if (!(adev->powerplay.pp_funcs &&
+ adev->powerplay.pp_funcs->read_sensor))
+ return -EINVAL;
+
+ /* get the sclk */
+ r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
+ (void *)&mclk, &size);
+ if (r)
+ return r;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", mclk * 10 * 1000);
+}
+
+static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "mclk\n");
+}
/**
* DOC: hwmon
@@ -1532,6 +1809,10 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
*
* - GPU fan
*
+ * - GPU gfx/compute engine clock
+ *
+ * - GPU memory clock (dGPU only)
+ *
* hwmon interfaces for GPU temperature:
*
* - temp1_input: the on die GPU temperature in millidegrees Celsius
@@ -1576,6 +1857,12 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
*
* - fan[1-*]_enable: Enable or disable the sensors.1: Enable 0: Disable
*
+ * hwmon interfaces for GPU clocks:
+ *
+ * - freq1_input: the gfx/compute clock in hertz
+ *
+ * - freq2_input: the memory clock in hertz
+ *
* You can use hwmon tools like sensors to view this information on your system.
*
*/
@@ -1600,6 +1887,10 @@ static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg,
static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);
+static SENSOR_DEVICE_ATTR(freq1_input, S_IRUGO, amdgpu_hwmon_show_sclk, NULL, 0);
+static SENSOR_DEVICE_ATTR(freq1_label, S_IRUGO, amdgpu_hwmon_show_sclk_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(freq2_input, S_IRUGO, amdgpu_hwmon_show_mclk, NULL, 0);
+static SENSOR_DEVICE_ATTR(freq2_label, S_IRUGO, amdgpu_hwmon_show_mclk_label, NULL, 0);
static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -1622,6 +1913,10 @@ static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_power1_cap_max.dev_attr.attr,
&sensor_dev_attr_power1_cap_min.dev_attr.attr,
&sensor_dev_attr_power1_cap.dev_attr.attr,
+ &sensor_dev_attr_freq1_input.dev_attr.attr,
+ &sensor_dev_attr_freq1_label.dev_attr.attr,
+ &sensor_dev_attr_freq2_input.dev_attr.attr,
+ &sensor_dev_attr_freq2_label.dev_attr.attr,
NULL
};
@@ -1686,7 +1981,8 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
effective_mode &= ~S_IWUSR;
if ((adev->flags & AMD_IS_APU) &&
- (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
+ (attr == &sensor_dev_attr_power1_average.dev_attr.attr ||
+ attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr||
attr == &sensor_dev_attr_power1_cap.dev_attr.attr))
return 0;
@@ -1712,6 +2008,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
attr == &sensor_dev_attr_in1_label.dev_attr.attr))
return 0;
+ /* no mclk on APUs */
+ if ((adev->flags & AMD_IS_APU) &&
+ (attr == &sensor_dev_attr_freq2_input.dev_attr.attr ||
+ attr == &sensor_dev_attr_freq2_label.dev_attr.attr))
+ return 0;
+
return effective_mode;
}
@@ -2008,6 +2310,7 @@ void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
{
+ struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
int ret;
if (adev->pm.sysfs_initialized)
@@ -2069,6 +2372,25 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
DRM_ERROR("failed to create device file pp_dpm_mclk\n");
return ret;
}
+ if (adev->asic_type >= CHIP_VEGA10) {
+ ret = device_create_file(adev->dev, &dev_attr_pp_dpm_socclk);
+ if (ret) {
+ DRM_ERROR("failed to create device file pp_dpm_socclk\n");
+ return ret;
+ }
+ ret = device_create_file(adev->dev, &dev_attr_pp_dpm_dcefclk);
+ if (ret) {
+ DRM_ERROR("failed to create device file pp_dpm_dcefclk\n");
+ return ret;
+ }
+ }
+ if (adev->asic_type >= CHIP_VEGA20) {
+ ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk);
+ if (ret) {
+ DRM_ERROR("failed to create device file pp_dpm_fclk\n");
+ return ret;
+ }
+ }
ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie);
if (ret) {
DRM_ERROR("failed to create device file pp_dpm_pcie\n");
@@ -2091,12 +2413,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
"pp_power_profile_mode\n");
return ret;
}
- ret = device_create_file(adev->dev,
- &dev_attr_pp_od_clk_voltage);
- if (ret) {
- DRM_ERROR("failed to create device file "
- "pp_od_clk_voltage\n");
- return ret;
+ if (hwmgr->od_enabled) {
+ ret = device_create_file(adev->dev,
+ &dev_attr_pp_od_clk_voltage);
+ if (ret) {
+ DRM_ERROR("failed to create device file "
+ "pp_od_clk_voltage\n");
+ return ret;
+ }
}
ret = device_create_file(adev->dev,
&dev_attr_gpu_busy_percent);
@@ -2105,12 +2429,31 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
"gpu_busy_level\n");
return ret;
}
+ /* PCIe Perf counters won't work on APU nodes */
+ if (!(adev->flags & AMD_IS_APU)) {
+ ret = device_create_file(adev->dev, &dev_attr_pcie_bw);
+ if (ret) {
+ DRM_ERROR("failed to create device file pcie_bw\n");
+ return ret;
+ }
+ }
ret = amdgpu_debugfs_pm_init(adev);
if (ret) {
DRM_ERROR("Failed to register debugfs file for dpm!\n");
return ret;
}
+ if ((adev->asic_type >= CHIP_VEGA10) &&
+ !(adev->flags & AMD_IS_APU)) {
+ ret = device_create_file(adev->dev,
+ &dev_attr_ppfeatures);
+ if (ret) {
+ DRM_ERROR("failed to create device file "
+ "ppfeatures\n");
+ return ret;
+ }
+ }
+
adev->pm.sysfs_initialized = true;
return 0;
@@ -2118,6 +2461,8 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
{
+ struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
+
if (adev->pm.dpm_enabled == 0)
return;
@@ -2133,14 +2478,26 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk);
device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk);
+ if (adev->asic_type >= CHIP_VEGA10) {
+ device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk);
+ device_remove_file(adev->dev, &dev_attr_pp_dpm_dcefclk);
+ }
device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
+ if (adev->asic_type >= CHIP_VEGA20)
+ device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk);
device_remove_file(adev->dev, &dev_attr_pp_sclk_od);
device_remove_file(adev->dev, &dev_attr_pp_mclk_od);
device_remove_file(adev->dev,
&dev_attr_pp_power_profile_mode);
- device_remove_file(adev->dev,
- &dev_attr_pp_od_clk_voltage);
+ if (hwmgr->od_enabled)
+ device_remove_file(adev->dev,
+ &dev_attr_pp_od_clk_voltage);
device_remove_file(adev->dev, &dev_attr_gpu_busy_percent);
+ if (!(adev->flags & AMD_IS_APU))
+ device_remove_file(adev->dev, &dev_attr_pcie_bw);
+ if ((adev->asic_type >= CHIP_VEGA10) &&
+ !(adev->flags & AMD_IS_APU))
+ device_remove_file(adev->dev, &dev_attr_ppfeatures);
}
void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
index 71913a18d142..a38e0fb4a6fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
@@ -38,6 +38,7 @@
#include "amdgpu_gem.h"
#include <drm/amdgpu_drm.h>
#include <linux/dma-buf.h>
+#include <linux/dma-fence-array.h>
/**
* amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table
@@ -187,6 +188,48 @@ error:
return ERR_PTR(ret);
}
+static int
+__reservation_object_make_exclusive(struct reservation_object *obj)
+{
+ struct dma_fence **fences;
+ unsigned int count;
+ int r;
+
+ if (!reservation_object_get_list(obj)) /* no shared fences to convert */
+ return 0;
+
+ r = reservation_object_get_fences_rcu(obj, NULL, &count, &fences);
+ if (r)
+ return r;
+
+ if (count == 0) {
+ /* Now that was unexpected. */
+ } else if (count == 1) {
+ reservation_object_add_excl_fence(obj, fences[0]);
+ dma_fence_put(fences[0]);
+ kfree(fences);
+ } else {
+ struct dma_fence_array *array;
+
+ array = dma_fence_array_create(count, fences,
+ dma_fence_context_alloc(1), 0,
+ false);
+ if (!array)
+ goto err_fences_put;
+
+ reservation_object_add_excl_fence(obj, &array->base);
+ dma_fence_put(&array->base);
+ }
+
+ return 0;
+
+err_fences_put:
+ while (count--)
+ dma_fence_put(fences[count]);
+ kfree(fences);
+ return -ENOMEM;
+}
+
/**
* amdgpu_gem_map_attach - &dma_buf_ops.attach implementation
* @dma_buf: Shared DMA buffer
@@ -218,16 +261,16 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf,
if (attach->dev->driver != adev->dev->driver) {
/*
- * Wait for all shared fences to complete before we switch to future
- * use of exclusive fence on this prime shared bo.
+ * We only create shared fences for internal use, but importers
+ * of the dmabuf rely on exclusive fences for implicitly
+ * tracking write hazards. As any of the current fences may
+ * correspond to a write, we need to convert all existing
+ * fences on the reservation object into a single exclusive
+ * fence.
*/
- r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
- true, false,
- MAX_SCHEDULE_TIMEOUT);
- if (unlikely(r < 0)) {
- DRM_DEBUG_PRIME("Fence wait failed: %li\n", r);
+ r = __reservation_object_make_exclusive(bo->tbo.resv);
+ if (r)
goto error_unreserve;
- }
}
/* pin buffer into GTT */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 8fab0d637ee5..3091488cd8cc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -67,9 +67,6 @@ static int psp_sw_init(void *handle)
psp->adev = adev;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
ret = psp_init_microcode(psp);
if (ret) {
DRM_ERROR("Failed to load psp firmware!\n");
@@ -83,15 +80,14 @@ static int psp_sw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
release_firmware(adev->psp.sos_fw);
adev->psp.sos_fw = NULL;
release_firmware(adev->psp.asd_fw);
adev->psp.asd_fw = NULL;
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
+ if (adev->psp.ta_fw) {
+ release_firmware(adev->psp.ta_fw);
+ adev->psp.ta_fw = NULL;
+ }
return 0;
}
@@ -140,13 +136,24 @@ psp_cmd_submit_buf(struct psp_context *psp,
while (*((unsigned int *)psp->fence_buf) != index)
msleep(1);
- /* the status field must be 0 after FW is loaded */
- if (ucode && psp->cmd_buf_mem->resp.status) {
- DRM_ERROR("failed loading with status (%d) and ucode id (%d)\n",
- psp->cmd_buf_mem->resp.status, ucode->ucode_id);
- return -EINVAL;
+ /* In some cases, psp response status is not 0 even there is no
+ * problem while the command is submitted. Some version of PSP FW
+ * doesn't write 0 to that field.
+ * So here we would like to only print a warning instead of an error
+ * during psp initialization to avoid breaking hw_init and it doesn't
+ * return -EINVAL.
+ */
+ if (psp->cmd_buf_mem->resp.status) {
+ if (ucode)
+ DRM_WARN("failed to load ucode id (%d) ",
+ ucode->ucode_id);
+ DRM_WARN("psp command failed and response status is (%d)\n",
+ psp->cmd_buf_mem->resp.status);
}
+ /* get xGMI session id from response buffer */
+ cmd->resp.session_id = psp->cmd_buf_mem->resp.session_id;
+
if (ucode) {
ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
@@ -435,6 +442,9 @@ static int psp_xgmi_initialize(struct psp_context *psp)
struct ta_xgmi_shared_memory *xgmi_cmd;
int ret;
+ if (!psp->adev->psp.ta_fw)
+ return -ENOENT;
+
if (!psp->xgmi_context.initialized) {
ret = psp_xgmi_init_shared_buf(psp);
if (ret)
@@ -495,6 +505,98 @@ static int psp_hw_start(struct psp_context *psp)
return 0;
}
+static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
+ enum psp_gfx_fw_type *type)
+{
+ switch (ucode->ucode_id) {
+ case AMDGPU_UCODE_ID_SDMA0:
+ *type = GFX_FW_TYPE_SDMA0;
+ break;
+ case AMDGPU_UCODE_ID_SDMA1:
+ *type = GFX_FW_TYPE_SDMA1;
+ break;
+ case AMDGPU_UCODE_ID_CP_CE:
+ *type = GFX_FW_TYPE_CP_CE;
+ break;
+ case AMDGPU_UCODE_ID_CP_PFP:
+ *type = GFX_FW_TYPE_CP_PFP;
+ break;
+ case AMDGPU_UCODE_ID_CP_ME:
+ *type = GFX_FW_TYPE_CP_ME;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC1:
+ *type = GFX_FW_TYPE_CP_MEC;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC1_JT:
+ *type = GFX_FW_TYPE_CP_MEC_ME1;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC2:
+ *type = GFX_FW_TYPE_CP_MEC;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC2_JT:
+ *type = GFX_FW_TYPE_CP_MEC_ME2;
+ break;
+ case AMDGPU_UCODE_ID_RLC_G:
+ *type = GFX_FW_TYPE_RLC_G;
+ break;
+ case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL:
+ *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL;
+ break;
+ case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM:
+ *type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM;
+ break;
+ case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM:
+ *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM;
+ break;
+ case AMDGPU_UCODE_ID_SMC:
+ *type = GFX_FW_TYPE_SMU;
+ break;
+ case AMDGPU_UCODE_ID_UVD:
+ *type = GFX_FW_TYPE_UVD;
+ break;
+ case AMDGPU_UCODE_ID_UVD1:
+ *type = GFX_FW_TYPE_UVD1;
+ break;
+ case AMDGPU_UCODE_ID_VCE:
+ *type = GFX_FW_TYPE_VCE;
+ break;
+ case AMDGPU_UCODE_ID_VCN:
+ *type = GFX_FW_TYPE_VCN;
+ break;
+ case AMDGPU_UCODE_ID_DMCU_ERAM:
+ *type = GFX_FW_TYPE_DMCU_ERAM;
+ break;
+ case AMDGPU_UCODE_ID_DMCU_INTV:
+ *type = GFX_FW_TYPE_DMCU_ISR;
+ break;
+ case AMDGPU_UCODE_ID_MAXIMUM:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode,
+ struct psp_gfx_cmd_resp *cmd)
+{
+ int ret;
+ uint64_t fw_mem_mc_addr = ucode->mc_addr;
+
+ memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
+
+ cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
+ cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr);
+ cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr);
+ cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size;
+
+ ret = psp_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type);
+ if (ret)
+ DRM_ERROR("Unknown firmware type\n");
+
+ return ret;
+}
+
static int psp_np_fw_load(struct psp_context *psp)
{
int i, ret;
@@ -516,7 +618,7 @@ static int psp_np_fw_load(struct psp_context *psp)
/*skip ucode loading in SRIOV VF */
continue;
- ret = psp_prep_cmd_buf(ucode, psp->cmd);
+ ret = psp_prep_load_ip_fw_cmd_buf(ucode, psp->cmd);
if (ret)
return ret;
@@ -541,7 +643,7 @@ static int psp_load_fw(struct amdgpu_device *adev)
struct psp_context *psp = &adev->psp;
if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset) {
- psp_ring_destroy(psp, PSP_RING_TYPE__KM);
+ psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */
goto skip_memalloc;
}
@@ -618,10 +720,6 @@ static int psp_hw_init(void *handle)
int ret;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
mutex_lock(&adev->firmware.mutex);
/*
* This sequence is just used on hw_init only once, no need on
@@ -651,9 +749,6 @@ static int psp_hw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
if (adev->gmc.xgmi.num_physical_nodes > 1 &&
psp->xgmi_context.initialized == 1)
psp_xgmi_terminate(psp);
@@ -682,9 +777,6 @@ static int psp_suspend(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
if (adev->gmc.xgmi.num_physical_nodes > 1 &&
psp->xgmi_context.initialized == 1) {
ret = psp_xgmi_terminate(psp);
@@ -709,9 +801,6 @@ static int psp_resume(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- return 0;
-
DRM_INFO("PSP is resuming...\n");
mutex_lock(&adev->firmware.mutex);
@@ -747,11 +836,6 @@ static bool psp_check_fw_loading_status(struct amdgpu_device *adev,
{
struct amdgpu_firmware_info *ucode = NULL;
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- DRM_INFO("firmware is not loaded by PSP\n");
- return true;
- }
-
if (!adev->firmware.fw_size)
return false;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 3ee573b4016e..2ef98cc755d6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -65,8 +65,6 @@ struct psp_funcs
int (*init_microcode)(struct psp_context *psp);
int (*bootloader_load_sysdrv)(struct psp_context *psp);
int (*bootloader_load_sos)(struct psp_context *psp);
- int (*prep_cmd_buf)(struct amdgpu_firmware_info *ucode,
- struct psp_gfx_cmd_resp *cmd);
int (*ring_init)(struct psp_context *psp, enum psp_ring_type ring_type);
int (*ring_create)(struct psp_context *psp,
enum psp_ring_type ring_type);
@@ -176,7 +174,6 @@ struct psp_xgmi_topology_info {
struct psp_xgmi_node_info nodes[AMDGPU_XGMI_MAX_CONNECTED_NODES];
};
-#define psp_prep_cmd_buf(ucode, type) (psp)->funcs->prep_cmd_buf((ucode), (type))
#define psp_ring_init(psp, type) (psp)->funcs->ring_init((psp), (type))
#define psp_ring_create(psp, type) (psp)->funcs->ring_create((psp), (type))
#define psp_ring_stop(psp, type) (psp)->funcs->ring_stop((psp), (type))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index d87e828a084b..d7fae2676269 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -131,7 +131,7 @@ struct amdgpu_ring_funcs {
void (*emit_ib)(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch);
+ uint32_t flags);
void (*emit_fence)(struct amdgpu_ring *ring, uint64_t addr,
uint64_t seq, unsigned flags);
void (*emit_pipeline_sync)(struct amdgpu_ring *ring);
@@ -229,7 +229,7 @@ struct amdgpu_ring {
#define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r))
#define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r))
#define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r))
-#define amdgpu_ring_emit_ib(r, job, ib, c) ((r)->funcs->emit_ib((r), (job), (ib), (c)))
+#define amdgpu_ring_emit_ib(r, job, ib, flags) ((r)->funcs->emit_ib((r), (job), (ib), (flags)))
#define amdgpu_ring_emit_pipeline_sync(r) (r)->funcs->emit_pipeline_sync((r))
#define amdgpu_ring_emit_vm_flush(r, vmid, addr) (r)->funcs->emit_vm_flush((r), (vmid), (addr))
#define amdgpu_ring_emit_fence(r, addr, seq, flags) (r)->funcs->emit_fence((r), (addr), (seq), (flags))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 626abca770a0..d3ca2424b5fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -76,9 +76,10 @@ TRACE_EVENT(amdgpu_mm_wreg,
);
TRACE_EVENT(amdgpu_iv,
- TP_PROTO(struct amdgpu_iv_entry *iv),
- TP_ARGS(iv),
+ TP_PROTO(unsigned ih, struct amdgpu_iv_entry *iv),
+ TP_ARGS(ih, iv),
TP_STRUCT__entry(
+ __field(unsigned, ih)
__field(unsigned, client_id)
__field(unsigned, src_id)
__field(unsigned, ring_id)
@@ -90,6 +91,7 @@ TRACE_EVENT(amdgpu_iv,
__array(unsigned, src_data, 4)
),
TP_fast_assign(
+ __entry->ih = ih;
__entry->client_id = iv->client_id;
__entry->src_id = iv->src_id;
__entry->ring_id = iv->ring_id;
@@ -103,8 +105,9 @@ TRACE_EVENT(amdgpu_iv,
__entry->src_data[2] = iv->src_data[2];
__entry->src_data[3] = iv->src_data[3];
),
- TP_printk("client_id:%u src_id:%u ring:%u vmid:%u timestamp: %llu pasid:%u src_data: %08x %08x %08x %08x",
- __entry->client_id, __entry->src_id,
+ TP_printk("ih:%u client_id:%u src_id:%u ring:%u vmid:%u "
+ "timestamp: %llu pasid:%u src_data: %08x %08x %08x %08x",
+ __entry->ih, __entry->client_id, __entry->src_id,
__entry->ring_id, __entry->vmid,
__entry->timestamp, __entry->pasid,
__entry->src_data[0], __entry->src_data[1],
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index c91ec3101d00..73e71e61dc99 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1546,7 +1546,8 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
.io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
.io_mem_free = &amdgpu_ttm_io_mem_free,
.io_mem_pfn = amdgpu_ttm_io_mem_pfn,
- .access_memory = &amdgpu_ttm_access_memory
+ .access_memory = &amdgpu_ttm_access_memory,
+ .del_from_lru_notify = &amdgpu_vm_del_from_lru_notify
};
/*
@@ -1755,7 +1756,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_kernel(adev, adev->gds.mem.gfx_partition_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_GDS,
+ 4, AMDGPU_GEM_DOMAIN_GDS,
&adev->gds.gds_gfx_bo, NULL, NULL);
if (r)
return r;
@@ -1768,7 +1769,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_kernel(adev, adev->gds.gws.gfx_partition_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_GWS,
+ 1, AMDGPU_GEM_DOMAIN_GWS,
&adev->gds.gws_gfx_bo, NULL, NULL);
if (r)
return r;
@@ -1781,7 +1782,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_kernel(adev, adev->gds.oa.gfx_partition_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_OA,
+ 1, AMDGPU_GEM_DOMAIN_OA,
&adev->gds.oa_gfx_bo, NULL, NULL);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 98a1b2ce2b9d..c021b114c8a4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -1035,7 +1035,7 @@ out:
void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
amdgpu_ring_write(ring, VCE_CMD_IB);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
index 50293652af14..30ea54dd9117 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -66,7 +66,7 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
- struct amdgpu_ib *ib, bool ctx_switch);
+ struct amdgpu_ib *ib, uint32_t flags);
void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
unsigned flags);
int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index e73d152659a2..7cd2336e29ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -107,14 +107,6 @@ struct amdgpu_pte_update_params {
* DMA addresses to use for mapping, used during VM update by CPU
*/
dma_addr_t *pages_addr;
-
- /**
- * @kptr:
- *
- * Kernel pointer of PD/PT BO that needs to be updated,
- * used during VM update by CPU
- */
- void *kptr;
};
/**
@@ -623,6 +615,28 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
list_add(&entry->tv.head, validated);
}
+void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo)
+{
+ struct amdgpu_bo *abo;
+ struct amdgpu_vm_bo_base *bo_base;
+
+ if (!amdgpu_bo_is_amdgpu_bo(bo))
+ return;
+
+ if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT)
+ return;
+
+ abo = ttm_to_amdgpu_bo(bo);
+ if (!abo->parent)
+ return;
+ for (bo_base = abo->vm_bo; bo_base; bo_base = bo_base->next) {
+ struct amdgpu_vm *vm = bo_base->vm;
+
+ if (abo->tbo.resv == vm->root.base.bo->tbo.resv)
+ vm->bulk_moveable = false;
+ }
+
+}
/**
* amdgpu_vm_move_to_lru_tail - move all BOs to the end of LRU
*
@@ -799,9 +813,16 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
addr += ats_entries * 8;
}
- if (entries)
+ if (entries) {
+ uint64_t value = 0;
+
+ /* Workaround for fault priority problem on GMC9 */
+ if (level == AMDGPU_VM_PTB && adev->asic_type >= CHIP_VEGA10)
+ value = AMDGPU_PTE_EXECUTABLE;
+
amdgpu_vm_set_pte_pde(adev, &job->ibs[0], addr, 0,
- entries, 0, 0);
+ entries, 0, value);
+ }
amdgpu_ring_pad_ib(ring, &job->ibs[0]);
@@ -847,9 +868,6 @@ static void amdgpu_vm_bo_param(struct amdgpu_device *adev, struct amdgpu_vm *vm,
bp->size = amdgpu_vm_bo_size(adev, level);
bp->byte_align = AMDGPU_GPU_PAGE_SIZE;
bp->domain = AMDGPU_GEM_DOMAIN_VRAM;
- if (bp->size <= PAGE_SIZE && adev->asic_type >= CHIP_VEGA10 &&
- adev->flags & AMD_IS_APU)
- bp->domain |= AMDGPU_GEM_DOMAIN_GTT;
bp->domain = amdgpu_bo_get_preferred_pin_domain(adev, bp->domain);
bp->flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
AMDGPU_GEM_CREATE_CPU_GTT_USWC;
@@ -1506,20 +1524,27 @@ error:
}
/**
- * amdgpu_vm_update_huge - figure out parameters for PTE updates
+ * amdgpu_vm_update_flags - figure out flags for PTE updates
*
* Make sure to set the right flags for the PTEs at the desired level.
*/
-static void amdgpu_vm_update_huge(struct amdgpu_pte_update_params *params,
- struct amdgpu_bo *bo, unsigned level,
- uint64_t pe, uint64_t addr,
- unsigned count, uint32_t incr,
- uint64_t flags)
+static void amdgpu_vm_update_flags(struct amdgpu_pte_update_params *params,
+ struct amdgpu_bo *bo, unsigned level,
+ uint64_t pe, uint64_t addr,
+ unsigned count, uint32_t incr,
+ uint64_t flags)
{
if (level != AMDGPU_VM_PTB) {
flags |= AMDGPU_PDE_PTE;
amdgpu_gmc_get_vm_pde(params->adev, level, &addr, &flags);
+
+ } else if (params->adev->asic_type >= CHIP_VEGA10 &&
+ !(flags & AMDGPU_PTE_VALID) &&
+ !(flags & AMDGPU_PTE_PRT)) {
+
+ /* Workaround for fault priority problem on GMC9 */
+ flags |= AMDGPU_PTE_EXECUTABLE;
}
amdgpu_vm_update_func(params, bo, pe, addr, count, incr, flags);
@@ -1676,9 +1701,9 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
uint64_t upd_end = min(entry_end, frag_end);
unsigned nptes = (upd_end - frag_start) >> shift;
- amdgpu_vm_update_huge(params, pt, cursor.level,
- pe_start, dst, nptes, incr,
- flags | AMDGPU_PTE_FRAG(frag));
+ amdgpu_vm_update_flags(params, pt, cursor.level,
+ pe_start, dst, nptes, incr,
+ flags | AMDGPU_PTE_FRAG(frag));
pe_start += nptes * 8;
dst += (uint64_t)nptes * AMDGPU_GPU_PAGE_SIZE << shift;
@@ -1756,13 +1781,20 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
if (pages_addr)
params.src = ~0;
- /* Wait for PT BOs to be free. PTs share the same resv. object
+ /* Wait for PT BOs to be idle. PTs share the same resv. object
* as the root PD BO
*/
r = amdgpu_vm_wait_pd(adev, vm, owner);
if (unlikely(r))
return r;
+ /* Wait for any BO move to be completed */
+ if (exclusive) {
+ r = dma_fence_wait(exclusive, true);
+ if (unlikely(r))
+ return r;
+ }
+
params.func = amdgpu_vm_cpu_set_ptes;
params.pages_addr = pages_addr;
return amdgpu_vm_update_ptes(&params, start, last + 1,
@@ -1776,13 +1808,12 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
/*
* reserve space for two commands every (1 << BLOCK_SIZE)
* entries or 2k dwords (whatever is smaller)
- *
- * The second command is for the shadow pagetables.
*/
+ ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1);
+
+ /* The second command is for the shadow pagetables. */
if (vm->root.base.bo->shadow)
- ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1) * 2;
- else
- ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1);
+ ncmds *= 2;
/* padding, etc. */
ndw = 64;
@@ -1801,10 +1832,11 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
ndw += ncmds * 10;
/* extra commands for begin/end fragments */
+ ncmds = 2 * adev->vm_manager.fragment_size;
if (vm->root.base.bo->shadow)
- ndw += 2 * 10 * adev->vm_manager.fragment_size * 2;
- else
- ndw += 2 * 10 * adev->vm_manager.fragment_size;
+ ncmds *= 2;
+
+ ndw += 10 * ncmds;
params.func = amdgpu_vm_do_set_ptes;
}
@@ -3006,7 +3038,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
}
DRM_DEBUG_DRIVER("VM update mode is %s\n",
vm->use_cpu_for_update ? "CPU" : "SDMA");
- WARN_ONCE((vm->use_cpu_for_update & !amdgpu_gmc_vram_full_visible(&adev->gmc)),
+ WARN_ONCE((vm->use_cpu_for_update && !amdgpu_gmc_vram_full_visible(&adev->gmc)),
"CPU update of VM recommended only for large BAR system\n");
vm->last_update = NULL;
@@ -3136,7 +3168,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, uns
vm->pte_support_ats = pte_support_ats;
DRM_DEBUG_DRIVER("VM update mode is %s\n",
vm->use_cpu_for_update ? "CPU" : "SDMA");
- WARN_ONCE((vm->use_cpu_for_update & !amdgpu_gmc_vram_full_visible(&adev->gmc)),
+ WARN_ONCE((vm->use_cpu_for_update && !amdgpu_gmc_vram_full_visible(&adev->gmc)),
"CPU update of VM recommended only for large BAR system\n");
if (vm->pasid) {
@@ -3366,14 +3398,15 @@ void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid,
struct amdgpu_task_info *task_info)
{
struct amdgpu_vm *vm;
+ unsigned long flags;
- spin_lock(&adev->vm_manager.pasid_lock);
+ spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
if (vm)
*task_info = vm->task_info;
- spin_unlock(&adev->vm_manager.pasid_lock);
+ spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index e8dcfd59fc93..81ff8177f092 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -363,4 +363,6 @@ int amdgpu_vm_add_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key)
void amdgpu_vm_clear_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key);
+void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo);
+
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
index 8a8bc60cb6b4..407dd16cc35c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -40,26 +40,40 @@ void *amdgpu_xgmi_hive_try_lock(struct amdgpu_hive_info *hive)
return &hive->device_list;
}
-struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
+struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev, int lock)
{
int i;
struct amdgpu_hive_info *tmp;
if (!adev->gmc.xgmi.hive_id)
return NULL;
+
+ mutex_lock(&xgmi_mutex);
+
for (i = 0 ; i < hive_count; ++i) {
tmp = &xgmi_hives[i];
- if (tmp->hive_id == adev->gmc.xgmi.hive_id)
+ if (tmp->hive_id == adev->gmc.xgmi.hive_id) {
+ if (lock)
+ mutex_lock(&tmp->hive_lock);
+ mutex_unlock(&xgmi_mutex);
return tmp;
+ }
}
- if (i >= AMDGPU_MAX_XGMI_HIVE)
+ if (i >= AMDGPU_MAX_XGMI_HIVE) {
+ mutex_unlock(&xgmi_mutex);
return NULL;
+ }
/* initialize new hive if not exist */
tmp = &xgmi_hives[hive_count++];
tmp->hive_id = adev->gmc.xgmi.hive_id;
INIT_LIST_HEAD(&tmp->device_list);
mutex_init(&tmp->hive_lock);
+ mutex_init(&tmp->reset_lock);
+ if (lock)
+ mutex_lock(&tmp->hive_lock);
+
+ mutex_unlock(&xgmi_mutex);
return tmp;
}
@@ -77,10 +91,6 @@ int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_dev
"XGMI: Set topology failure on device %llx, hive %llx, ret %d",
adev->gmc.xgmi.node_id,
adev->gmc.xgmi.hive_id, ret);
- else
- dev_info(adev->dev, "XGMI: Set topology for node %d, hive 0x%llx.\n",
- adev->gmc.xgmi.physical_node_id,
- adev->gmc.xgmi.hive_id);
return ret;
}
@@ -111,10 +121,14 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
return ret;
}
- mutex_lock(&xgmi_mutex);
- hive = amdgpu_get_xgmi_hive(adev);
- if (!hive)
+ hive = amdgpu_get_xgmi_hive(adev, 1);
+ if (!hive) {
+ ret = -EINVAL;
+ dev_err(adev->dev,
+ "XGMI: node 0x%llx, can not match hive 0x%llx in the hive list.\n",
+ adev->gmc.xgmi.node_id, adev->gmc.xgmi.hive_id);
goto exit;
+ }
hive_topology = &hive->topology_info;
@@ -142,8 +156,11 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
break;
}
+ dev_info(adev->dev, "XGMI: Add node %d, hive 0x%llx.\n",
+ adev->gmc.xgmi.physical_node_id, adev->gmc.xgmi.hive_id);
+
+ mutex_unlock(&hive->hive_lock);
exit:
- mutex_unlock(&xgmi_mutex);
return ret;
}
@@ -154,15 +171,14 @@ void amdgpu_xgmi_remove_device(struct amdgpu_device *adev)
if (!adev->gmc.xgmi.supported)
return;
- mutex_lock(&xgmi_mutex);
-
- hive = amdgpu_get_xgmi_hive(adev);
+ hive = amdgpu_get_xgmi_hive(adev, 1);
if (!hive)
- goto exit;
+ return;
- if (!(hive->number_devices--))
+ if (!(hive->number_devices--)) {
mutex_destroy(&hive->hive_lock);
-
-exit:
- mutex_unlock(&xgmi_mutex);
+ mutex_destroy(&hive->reset_lock);
+ } else {
+ mutex_unlock(&hive->hive_lock);
+ }
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
index 6151eb9c8ad3..14bc60664159 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
@@ -29,10 +29,11 @@ struct amdgpu_hive_info {
struct list_head device_list;
struct psp_xgmi_topology_info topology_info;
int number_devices;
- struct mutex hive_lock;
+ struct mutex hive_lock,
+ reset_lock;
};
-struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev);
+struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev, int lock);
int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev);
int amdgpu_xgmi_add_device(struct amdgpu_device *adev);
void amdgpu_xgmi_remove_device(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
deleted file mode 100644
index 86e14c754dd4..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ /dev/null
@@ -1,6844 +0,0 @@
-/*
- * Copyright 2013 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <linux/firmware.h>
-#include <drm/drmP.h>
-#include "amdgpu.h"
-#include "amdgpu_pm.h"
-#include "amdgpu_ucode.h"
-#include "cikd.h"
-#include "amdgpu_dpm.h"
-#include "ci_dpm.h"
-#include "gfx_v7_0.h"
-#include "atom.h"
-#include "amd_pcie.h"
-#include <linux/seq_file.h>
-
-#include "smu/smu_7_0_1_d.h"
-#include "smu/smu_7_0_1_sh_mask.h"
-
-#include "dce/dce_8_0_d.h"
-#include "dce/dce_8_0_sh_mask.h"
-
-#include "bif/bif_4_1_d.h"
-#include "bif/bif_4_1_sh_mask.h"
-
-#include "gca/gfx_7_2_d.h"
-#include "gca/gfx_7_2_sh_mask.h"
-
-#include "gmc/gmc_7_1_d.h"
-#include "gmc/gmc_7_1_sh_mask.h"
-
-MODULE_FIRMWARE("amdgpu/bonaire_smc.bin");
-MODULE_FIRMWARE("amdgpu/bonaire_k_smc.bin");
-MODULE_FIRMWARE("amdgpu/hawaii_smc.bin");
-MODULE_FIRMWARE("amdgpu/hawaii_k_smc.bin");
-
-#define MC_CG_ARB_FREQ_F0 0x0a
-#define MC_CG_ARB_FREQ_F1 0x0b
-#define MC_CG_ARB_FREQ_F2 0x0c
-#define MC_CG_ARB_FREQ_F3 0x0d
-
-#define SMC_RAM_END 0x40000
-
-#define VOLTAGE_SCALE 4
-#define VOLTAGE_VID_OFFSET_SCALE1 625
-#define VOLTAGE_VID_OFFSET_SCALE2 100
-
-static const struct amd_pm_funcs ci_dpm_funcs;
-
-static const struct ci_pt_defaults defaults_hawaii_xt =
-{
- 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
- { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
- { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
-};
-
-static const struct ci_pt_defaults defaults_hawaii_pro =
-{
- 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
- { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
- { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
-};
-
-static const struct ci_pt_defaults defaults_bonaire_xt =
-{
- 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
- { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 },
- { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
-};
-
-#if 0
-static const struct ci_pt_defaults defaults_bonaire_pro =
-{
- 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x65062,
- { 0x8C, 0x23F, 0x244, 0xA6, 0x83, 0x85, 0x86, 0x86, 0x83, 0xDB, 0xDB, 0xDA, 0x67, 0x60, 0x5F },
- { 0x187, 0x193, 0x193, 0x1C7, 0x1D1, 0x1D1, 0x210, 0x219, 0x219, 0x266, 0x26C, 0x26C, 0x2C9, 0x2CB, 0x2CB }
-};
-#endif
-
-static const struct ci_pt_defaults defaults_saturn_xt =
-{
- 1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
- { 0x8C, 0x247, 0x249, 0xA6, 0x80, 0x81, 0x8B, 0x89, 0x86, 0xC9, 0xCA, 0xC9, 0x4D, 0x4D, 0x4D },
- { 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
-};
-
-#if 0
-static const struct ci_pt_defaults defaults_saturn_pro =
-{
- 1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x30000,
- { 0x96, 0x21D, 0x23B, 0xA1, 0x85, 0x87, 0x83, 0x84, 0x81, 0xE6, 0xE6, 0xE6, 0x71, 0x6A, 0x6A },
- { 0x193, 0x19E, 0x19E, 0x1D2, 0x1DC, 0x1DC, 0x21A, 0x223, 0x223, 0x26E, 0x27E, 0x274, 0x2CF, 0x2D2, 0x2D2 }
-};
-#endif
-
-static const struct ci_pt_config_reg didt_config_ci[] =
-{
- { 0x10, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x10, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x10, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x10, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x11, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x11, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x11, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x11, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x12, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x12, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x12, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x12, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x2, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x2, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x2, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x1, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x1, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x0, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x30, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x30, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x30, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x30, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x31, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x31, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x31, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x31, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x32, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x32, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x32, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x32, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x22, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x22, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x22, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x21, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x21, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x20, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x50, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x50, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x50, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x50, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x51, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x51, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x51, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x51, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x52, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x52, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x52, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x52, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x42, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x42, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x42, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x41, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x41, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x40, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x70, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x70, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x70, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x70, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x71, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x71, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x71, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x71, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x72, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x72, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x72, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x72, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x62, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x62, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x62, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x61, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x61, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
- { 0x60, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
- { 0xFFFFFFFF }
-};
-
-static u8 ci_get_memory_module_index(struct amdgpu_device *adev)
-{
- return (u8) ((RREG32(mmBIOS_SCRATCH_4) >> 16) & 0xff);
-}
-
-#define MC_CG_ARB_FREQ_F0 0x0a
-#define MC_CG_ARB_FREQ_F1 0x0b
-#define MC_CG_ARB_FREQ_F2 0x0c
-#define MC_CG_ARB_FREQ_F3 0x0d
-
-static int ci_copy_and_switch_arb_sets(struct amdgpu_device *adev,
- u32 arb_freq_src, u32 arb_freq_dest)
-{
- u32 mc_arb_dram_timing;
- u32 mc_arb_dram_timing2;
- u32 burst_time;
- u32 mc_cg_config;
-
- switch (arb_freq_src) {
- case MC_CG_ARB_FREQ_F0:
- mc_arb_dram_timing = RREG32(mmMC_ARB_DRAM_TIMING);
- mc_arb_dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2);
- burst_time = (RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE0_MASK) >>
- MC_ARB_BURST_TIME__STATE0__SHIFT;
- break;
- case MC_CG_ARB_FREQ_F1:
- mc_arb_dram_timing = RREG32(mmMC_ARB_DRAM_TIMING_1);
- mc_arb_dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2_1);
- burst_time = (RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE1_MASK) >>
- MC_ARB_BURST_TIME__STATE1__SHIFT;
- break;
- default:
- return -EINVAL;
- }
-
- switch (arb_freq_dest) {
- case MC_CG_ARB_FREQ_F0:
- WREG32(mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
- WREG32(mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
- WREG32_P(mmMC_ARB_BURST_TIME, (burst_time << MC_ARB_BURST_TIME__STATE0__SHIFT),
- ~MC_ARB_BURST_TIME__STATE0_MASK);
- break;
- case MC_CG_ARB_FREQ_F1:
- WREG32(mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
- WREG32(mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
- WREG32_P(mmMC_ARB_BURST_TIME, (burst_time << MC_ARB_BURST_TIME__STATE1__SHIFT),
- ~MC_ARB_BURST_TIME__STATE1_MASK);
- break;
- default:
- return -EINVAL;
- }
-
- mc_cg_config = RREG32(mmMC_CG_CONFIG) | 0x0000000F;
- WREG32(mmMC_CG_CONFIG, mc_cg_config);
- WREG32_P(mmMC_ARB_CG, (arb_freq_dest) << MC_ARB_CG__CG_ARB_REQ__SHIFT,
- ~MC_ARB_CG__CG_ARB_REQ_MASK);
-
- return 0;
-}
-
-static u8 ci_get_ddr3_mclk_frequency_ratio(u32 memory_clock)
-{
- u8 mc_para_index;
-
- if (memory_clock < 10000)
- mc_para_index = 0;
- else if (memory_clock >= 80000)
- mc_para_index = 0x0f;
- else
- mc_para_index = (u8)((memory_clock - 10000) / 5000 + 1);
- return mc_para_index;
-}
-
-static u8 ci_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode)
-{
- u8 mc_para_index;
-
- if (strobe_mode) {
- if (memory_clock < 12500)
- mc_para_index = 0x00;
- else if (memory_clock > 47500)
- mc_para_index = 0x0f;
- else
- mc_para_index = (u8)((memory_clock - 10000) / 2500);
- } else {
- if (memory_clock < 65000)
- mc_para_index = 0x00;
- else if (memory_clock > 135000)
- mc_para_index = 0x0f;
- else
- mc_para_index = (u8)((memory_clock - 60000) / 5000);
- }
- return mc_para_index;
-}
-
-static void ci_trim_voltage_table_to_fit_state_table(struct amdgpu_device *adev,
- u32 max_voltage_steps,
- struct atom_voltage_table *voltage_table)
-{
- unsigned int i, diff;
-
- if (voltage_table->count <= max_voltage_steps)
- return;
-
- diff = voltage_table->count - max_voltage_steps;
-
- for (i = 0; i < max_voltage_steps; i++)
- voltage_table->entries[i] = voltage_table->entries[i + diff];
-
- voltage_table->count = max_voltage_steps;
-}
-
-static int ci_get_std_voltage_value_sidd(struct amdgpu_device *adev,
- struct atom_voltage_table_entry *voltage_table,
- u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd);
-static int ci_set_power_limit(struct amdgpu_device *adev, u32 n);
-static int ci_set_overdrive_target_tdp(struct amdgpu_device *adev,
- u32 target_tdp);
-static int ci_update_uvd_dpm(struct amdgpu_device *adev, bool gate);
-static void ci_dpm_set_irq_funcs(struct amdgpu_device *adev);
-
-static PPSMC_Result amdgpu_ci_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
- PPSMC_Msg msg, u32 parameter);
-static void ci_thermal_start_smc_fan_control(struct amdgpu_device *adev);
-static void ci_fan_ctrl_set_default_mode(struct amdgpu_device *adev);
-
-static struct ci_power_info *ci_get_pi(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = adev->pm.dpm.priv;
-
- return pi;
-}
-
-static struct ci_ps *ci_get_ps(struct amdgpu_ps *rps)
-{
- struct ci_ps *ps = rps->ps_priv;
-
- return ps;
-}
-
-static void ci_initialize_powertune_defaults(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- switch (adev->pdev->device) {
- case 0x6649:
- case 0x6650:
- case 0x6651:
- case 0x6658:
- case 0x665C:
- case 0x665D:
- default:
- pi->powertune_defaults = &defaults_bonaire_xt;
- break;
- case 0x6640:
- case 0x6641:
- case 0x6646:
- case 0x6647:
- pi->powertune_defaults = &defaults_saturn_xt;
- break;
- case 0x67B8:
- case 0x67B0:
- pi->powertune_defaults = &defaults_hawaii_xt;
- break;
- case 0x67BA:
- case 0x67B1:
- pi->powertune_defaults = &defaults_hawaii_pro;
- break;
- case 0x67A0:
- case 0x67A1:
- case 0x67A2:
- case 0x67A8:
- case 0x67A9:
- case 0x67AA:
- case 0x67B9:
- case 0x67BE:
- pi->powertune_defaults = &defaults_bonaire_xt;
- break;
- }
-
- pi->dte_tj_offset = 0;
-
- pi->caps_power_containment = true;
- pi->caps_cac = false;
- pi->caps_sq_ramping = false;
- pi->caps_db_ramping = false;
- pi->caps_td_ramping = false;
- pi->caps_tcp_ramping = false;
-
- if (pi->caps_power_containment) {
- pi->caps_cac = true;
- if (adev->asic_type == CHIP_HAWAII)
- pi->enable_bapm_feature = false;
- else
- pi->enable_bapm_feature = true;
- pi->enable_tdc_limit_feature = true;
- pi->enable_pkg_pwr_tracking_feature = true;
- }
-}
-
-static u8 ci_convert_to_vid(u16 vddc)
-{
- return (6200 - (vddc * VOLTAGE_SCALE)) / 25;
-}
-
-static int ci_populate_bapm_vddc_vid_sidd(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
- u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
- u8 *hi2_vid = pi->smc_powertune_table.BapmVddCVidHiSidd2;
- u32 i;
-
- if (adev->pm.dpm.dyn_state.cac_leakage_table.entries == NULL)
- return -EINVAL;
- if (adev->pm.dpm.dyn_state.cac_leakage_table.count > 8)
- return -EINVAL;
- if (adev->pm.dpm.dyn_state.cac_leakage_table.count !=
- adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count)
- return -EINVAL;
-
- for (i = 0; i < adev->pm.dpm.dyn_state.cac_leakage_table.count; i++) {
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
- lo_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1);
- hi_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2);
- hi2_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3);
- } else {
- lo_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc);
- hi_vid[i] = ci_convert_to_vid((u16)adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage);
- }
- }
- return 0;
-}
-
-static int ci_populate_vddc_vid(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u8 *vid = pi->smc_powertune_table.VddCVid;
- u32 i;
-
- if (pi->vddc_voltage_table.count > 8)
- return -EINVAL;
-
- for (i = 0; i < pi->vddc_voltage_table.count; i++)
- vid[i] = ci_convert_to_vid(pi->vddc_voltage_table.entries[i].value);
-
- return 0;
-}
-
-static int ci_populate_svi_load_line(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
-
- pi->smc_powertune_table.SviLoadLineEn = pt_defaults->svi_load_line_en;
- pi->smc_powertune_table.SviLoadLineVddC = pt_defaults->svi_load_line_vddc;
- pi->smc_powertune_table.SviLoadLineTrimVddC = 3;
- pi->smc_powertune_table.SviLoadLineOffsetVddC = 0;
-
- return 0;
-}
-
-static int ci_populate_tdc_limit(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
- u16 tdc_limit;
-
- tdc_limit = adev->pm.dpm.dyn_state.cac_tdp_table->tdc * 256;
- pi->smc_powertune_table.TDC_VDDC_PkgLimit = cpu_to_be16(tdc_limit);
- pi->smc_powertune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
- pt_defaults->tdc_vddc_throttle_release_limit_perc;
- pi->smc_powertune_table.TDC_MAWt = pt_defaults->tdc_mawt;
-
- return 0;
-}
-
-static int ci_populate_dw8(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
- int ret;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, PmFuseTable) +
- offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
- (u32 *)&pi->smc_powertune_table.TdcWaterfallCtl,
- pi->sram_end);
- if (ret)
- return -EINVAL;
- else
- pi->smc_powertune_table.TdcWaterfallCtl = pt_defaults->tdc_waterfall_ctl;
-
- return 0;
-}
-
-static int ci_populate_fuzzy_fan(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if ((adev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
- (adev->pm.dpm.fan.fan_output_sensitivity == 0))
- adev->pm.dpm.fan.fan_output_sensitivity =
- adev->pm.dpm.fan.default_fan_output_sensitivity;
-
- pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
- cpu_to_be16(adev->pm.dpm.fan.fan_output_sensitivity);
-
- return 0;
-}
-
-static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
- u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
- int i, min, max;
-
- min = max = hi_vid[0];
- for (i = 0; i < 8; i++) {
- if (0 != hi_vid[i]) {
- if (min > hi_vid[i])
- min = hi_vid[i];
- if (max < hi_vid[i])
- max = hi_vid[i];
- }
-
- if (0 != lo_vid[i]) {
- if (min > lo_vid[i])
- min = lo_vid[i];
- if (max < lo_vid[i])
- max = lo_vid[i];
- }
- }
-
- if ((min == 0) || (max == 0))
- return -EINVAL;
- pi->smc_powertune_table.GnbLPMLMaxVid = (u8)max;
- pi->smc_powertune_table.GnbLPMLMinVid = (u8)min;
-
- return 0;
-}
-
-static int ci_populate_bapm_vddc_base_leakage_sidd(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u16 hi_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd;
- u16 lo_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd;
- struct amdgpu_cac_tdp_table *cac_tdp_table =
- adev->pm.dpm.dyn_state.cac_tdp_table;
-
- hi_sidd = cac_tdp_table->high_cac_leakage / 100 * 256;
- lo_sidd = cac_tdp_table->low_cac_leakage / 100 * 256;
-
- pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd = cpu_to_be16(hi_sidd);
- pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd = cpu_to_be16(lo_sidd);
-
- return 0;
-}
-
-static int ci_populate_bapm_parameters_in_dpm_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
- SMU7_Discrete_DpmTable *dpm_table = &pi->smc_state_table;
- struct amdgpu_cac_tdp_table *cac_tdp_table =
- adev->pm.dpm.dyn_state.cac_tdp_table;
- struct amdgpu_ppm_table *ppm = adev->pm.dpm.dyn_state.ppm_table;
- int i, j, k;
- const u16 *def1;
- const u16 *def2;
-
- dpm_table->DefaultTdp = cac_tdp_table->tdp * 256;
- dpm_table->TargetTdp = cac_tdp_table->configurable_tdp * 256;
-
- dpm_table->DTETjOffset = (u8)pi->dte_tj_offset;
- dpm_table->GpuTjMax =
- (u8)(pi->thermal_temp_setting.temperature_high / 1000);
- dpm_table->GpuTjHyst = 8;
-
- dpm_table->DTEAmbientTempBase = pt_defaults->dte_ambient_temp_base;
-
- if (ppm) {
- dpm_table->PPM_PkgPwrLimit = cpu_to_be16((u16)ppm->dgpu_tdp * 256 / 1000);
- dpm_table->PPM_TemperatureLimit = cpu_to_be16((u16)ppm->tj_max * 256);
- } else {
- dpm_table->PPM_PkgPwrLimit = cpu_to_be16(0);
- dpm_table->PPM_TemperatureLimit = cpu_to_be16(0);
- }
-
- dpm_table->BAPM_TEMP_GRADIENT = cpu_to_be32(pt_defaults->bapm_temp_gradient);
- def1 = pt_defaults->bapmti_r;
- def2 = pt_defaults->bapmti_rc;
-
- for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
- for (j = 0; j < SMU7_DTE_SOURCES; j++) {
- for (k = 0; k < SMU7_DTE_SINKS; k++) {
- dpm_table->BAPMTI_R[i][j][k] = cpu_to_be16(*def1);
- dpm_table->BAPMTI_RC[i][j][k] = cpu_to_be16(*def2);
- def1++;
- def2++;
- }
- }
- }
-
- return 0;
-}
-
-static int ci_populate_pm_base(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 pm_fuse_table_offset;
- int ret;
-
- if (pi->caps_power_containment) {
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, PmFuseTable),
- &pm_fuse_table_offset, pi->sram_end);
- if (ret)
- return ret;
- ret = ci_populate_bapm_vddc_vid_sidd(adev);
- if (ret)
- return ret;
- ret = ci_populate_vddc_vid(adev);
- if (ret)
- return ret;
- ret = ci_populate_svi_load_line(adev);
- if (ret)
- return ret;
- ret = ci_populate_tdc_limit(adev);
- if (ret)
- return ret;
- ret = ci_populate_dw8(adev);
- if (ret)
- return ret;
- ret = ci_populate_fuzzy_fan(adev);
- if (ret)
- return ret;
- ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(adev);
- if (ret)
- return ret;
- ret = ci_populate_bapm_vddc_base_leakage_sidd(adev);
- if (ret)
- return ret;
- ret = amdgpu_ci_copy_bytes_to_smc(adev, pm_fuse_table_offset,
- (u8 *)&pi->smc_powertune_table,
- sizeof(SMU7_Discrete_PmFuses), pi->sram_end);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static void ci_do_enable_didt(struct amdgpu_device *adev, const bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 data;
-
- if (pi->caps_sq_ramping) {
- data = RREG32_DIDT(ixDIDT_SQ_CTRL0);
- if (enable)
- data |= DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
- else
- data &= ~DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
- WREG32_DIDT(ixDIDT_SQ_CTRL0, data);
- }
-
- if (pi->caps_db_ramping) {
- data = RREG32_DIDT(ixDIDT_DB_CTRL0);
- if (enable)
- data |= DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
- else
- data &= ~DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
- WREG32_DIDT(ixDIDT_DB_CTRL0, data);
- }
-
- if (pi->caps_td_ramping) {
- data = RREG32_DIDT(ixDIDT_TD_CTRL0);
- if (enable)
- data |= DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
- else
- data &= ~DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
- WREG32_DIDT(ixDIDT_TD_CTRL0, data);
- }
-
- if (pi->caps_tcp_ramping) {
- data = RREG32_DIDT(ixDIDT_TCP_CTRL0);
- if (enable)
- data |= DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
- else
- data &= ~DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
- WREG32_DIDT(ixDIDT_TCP_CTRL0, data);
- }
-}
-
-static int ci_program_pt_config_registers(struct amdgpu_device *adev,
- const struct ci_pt_config_reg *cac_config_regs)
-{
- const struct ci_pt_config_reg *config_regs = cac_config_regs;
- u32 data;
- u32 cache = 0;
-
- if (config_regs == NULL)
- return -EINVAL;
-
- while (config_regs->offset != 0xFFFFFFFF) {
- if (config_regs->type == CISLANDS_CONFIGREG_CACHE) {
- cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
- } else {
- switch (config_regs->type) {
- case CISLANDS_CONFIGREG_SMC_IND:
- data = RREG32_SMC(config_regs->offset);
- break;
- case CISLANDS_CONFIGREG_DIDT_IND:
- data = RREG32_DIDT(config_regs->offset);
- break;
- default:
- data = RREG32(config_regs->offset);
- break;
- }
-
- data &= ~config_regs->mask;
- data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
- data |= cache;
-
- switch (config_regs->type) {
- case CISLANDS_CONFIGREG_SMC_IND:
- WREG32_SMC(config_regs->offset, data);
- break;
- case CISLANDS_CONFIGREG_DIDT_IND:
- WREG32_DIDT(config_regs->offset, data);
- break;
- default:
- WREG32(config_regs->offset, data);
- break;
- }
- cache = 0;
- }
- config_regs++;
- }
- return 0;
-}
-
-static int ci_enable_didt(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
-
- if (pi->caps_sq_ramping || pi->caps_db_ramping ||
- pi->caps_td_ramping || pi->caps_tcp_ramping) {
- amdgpu_gfx_rlc_enter_safe_mode(adev);
-
- if (enable) {
- ret = ci_program_pt_config_registers(adev, didt_config_ci);
- if (ret) {
- amdgpu_gfx_rlc_exit_safe_mode(adev);
- return ret;
- }
- }
-
- ci_do_enable_didt(adev, enable);
-
- amdgpu_gfx_rlc_exit_safe_mode(adev);
- }
-
- return 0;
-}
-
-static int ci_enable_power_containment(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
- int ret = 0;
-
- if (enable) {
- pi->power_containment_features = 0;
- if (pi->caps_power_containment) {
- if (pi->enable_bapm_feature) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableDTE);
- if (smc_result != PPSMC_Result_OK)
- ret = -EINVAL;
- else
- pi->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
- }
-
- if (pi->enable_tdc_limit_feature) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_TDCLimitEnable);
- if (smc_result != PPSMC_Result_OK)
- ret = -EINVAL;
- else
- pi->power_containment_features |= POWERCONTAINMENT_FEATURE_TDCLimit;
- }
-
- if (pi->enable_pkg_pwr_tracking_feature) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PkgPwrLimitEnable);
- if (smc_result != PPSMC_Result_OK) {
- ret = -EINVAL;
- } else {
- struct amdgpu_cac_tdp_table *cac_tdp_table =
- adev->pm.dpm.dyn_state.cac_tdp_table;
- u32 default_pwr_limit =
- (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
-
- pi->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit;
-
- ci_set_power_limit(adev, default_pwr_limit);
- }
- }
- }
- } else {
- if (pi->caps_power_containment && pi->power_containment_features) {
- if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_TDCLimit)
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_TDCLimitDisable);
-
- if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableDTE);
-
- if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit)
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PkgPwrLimitDisable);
- pi->power_containment_features = 0;
- }
- }
-
- return ret;
-}
-
-static int ci_enable_smc_cac(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
- int ret = 0;
-
- if (pi->caps_cac) {
- if (enable) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableCac);
- if (smc_result != PPSMC_Result_OK) {
- ret = -EINVAL;
- pi->cac_enabled = false;
- } else {
- pi->cac_enabled = true;
- }
- } else if (pi->cac_enabled) {
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableCac);
- pi->cac_enabled = false;
- }
- }
-
- return ret;
-}
-
-static int ci_enable_thermal_based_sclk_dpm(struct amdgpu_device *adev,
- bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result = PPSMC_Result_OK;
-
- if (pi->thermal_sclk_dpm_enabled) {
- if (enable)
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_ENABLE_THERMAL_DPM);
- else
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DISABLE_THERMAL_DPM);
- }
-
- if (smc_result == PPSMC_Result_OK)
- return 0;
- else
- return -EINVAL;
-}
-
-static int ci_power_control_set_level(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_cac_tdp_table *cac_tdp_table =
- adev->pm.dpm.dyn_state.cac_tdp_table;
- s32 adjust_percent;
- s32 target_tdp;
- int ret = 0;
- bool adjust_polarity = false; /* ??? */
-
- if (pi->caps_power_containment) {
- adjust_percent = adjust_polarity ?
- adev->pm.dpm.tdp_adjustment : (-1 * adev->pm.dpm.tdp_adjustment);
- target_tdp = ((100 + adjust_percent) *
- (s32)cac_tdp_table->configurable_tdp) / 100;
-
- ret = ci_set_overdrive_target_tdp(adev, (u32)target_tdp);
- }
-
- return ret;
-}
-
-static void ci_dpm_powergate_uvd(void *handle, bool gate)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- pi->uvd_power_gated = gate;
-
- if (gate) {
- /* stop the UVD block */
- amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_PG_STATE_GATE);
- ci_update_uvd_dpm(adev, gate);
- } else {
- amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_PG_STATE_UNGATE);
- ci_update_uvd_dpm(adev, gate);
- }
-}
-
-static bool ci_dpm_vblank_too_short(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
- u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
-
- /* disable mclk switching if the refresh is >120Hz, even if the
- * blanking period would allow it
- */
- if (amdgpu_dpm_get_vrefresh(adev) > 120)
- return true;
-
- if (vblank_time < switch_limit)
- return true;
- else
- return false;
-
-}
-
-static void ci_apply_state_adjust_rules(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- struct ci_ps *ps = ci_get_ps(rps);
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_clock_and_voltage_limits *max_limits;
- bool disable_mclk_switching;
- u32 sclk, mclk;
- int i;
-
- if (rps->vce_active) {
- rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
- rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk;
- } else {
- rps->evclk = 0;
- rps->ecclk = 0;
- }
-
- if ((adev->pm.dpm.new_active_crtc_count > 1) ||
- ci_dpm_vblank_too_short(adev))
- disable_mclk_switching = true;
- else
- disable_mclk_switching = false;
-
- if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
- pi->battery_state = true;
- else
- pi->battery_state = false;
-
- if (adev->pm.ac_power)
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- else
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
-
- if (adev->pm.ac_power == false) {
- for (i = 0; i < ps->performance_level_count; i++) {
- if (ps->performance_levels[i].mclk > max_limits->mclk)
- ps->performance_levels[i].mclk = max_limits->mclk;
- if (ps->performance_levels[i].sclk > max_limits->sclk)
- ps->performance_levels[i].sclk = max_limits->sclk;
- }
- }
-
- /* XXX validate the min clocks required for display */
-
- if (disable_mclk_switching) {
- mclk = ps->performance_levels[ps->performance_level_count - 1].mclk;
- sclk = ps->performance_levels[0].sclk;
- } else {
- mclk = ps->performance_levels[0].mclk;
- sclk = ps->performance_levels[0].sclk;
- }
-
- if (adev->pm.pm_display_cfg.min_core_set_clock > sclk)
- sclk = adev->pm.pm_display_cfg.min_core_set_clock;
-
- if (adev->pm.pm_display_cfg.min_mem_set_clock > mclk)
- mclk = adev->pm.pm_display_cfg.min_mem_set_clock;
-
- if (rps->vce_active) {
- if (sclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk)
- sclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk;
- if (mclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk)
- mclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk;
- }
-
- ps->performance_levels[0].sclk = sclk;
- ps->performance_levels[0].mclk = mclk;
-
- if (ps->performance_levels[1].sclk < ps->performance_levels[0].sclk)
- ps->performance_levels[1].sclk = ps->performance_levels[0].sclk;
-
- if (disable_mclk_switching) {
- if (ps->performance_levels[0].mclk < ps->performance_levels[1].mclk)
- ps->performance_levels[0].mclk = ps->performance_levels[1].mclk;
- } else {
- if (ps->performance_levels[1].mclk < ps->performance_levels[0].mclk)
- ps->performance_levels[1].mclk = ps->performance_levels[0].mclk;
- }
-}
-
-static int ci_thermal_set_temperature_range(struct amdgpu_device *adev,
- int min_temp, int max_temp)
-{
- int low_temp = 0 * 1000;
- int high_temp = 255 * 1000;
- u32 tmp;
-
- if (low_temp < min_temp)
- low_temp = min_temp;
- if (high_temp > max_temp)
- high_temp = max_temp;
- if (high_temp < low_temp) {
- DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
- return -EINVAL;
- }
-
- tmp = RREG32_SMC(ixCG_THERMAL_INT);
- tmp &= ~(CG_THERMAL_INT__DIG_THERM_INTH_MASK | CG_THERMAL_INT__DIG_THERM_INTL_MASK);
- tmp |= ((high_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTH__SHIFT) |
- ((low_temp / 1000)) << CG_THERMAL_INT__DIG_THERM_INTL__SHIFT;
- WREG32_SMC(ixCG_THERMAL_INT, tmp);
-
-#if 0
- /* XXX: need to figure out how to handle this properly */
- tmp = RREG32_SMC(ixCG_THERMAL_CTRL);
- tmp &= DIG_THERM_DPM_MASK;
- tmp |= DIG_THERM_DPM(high_temp / 1000);
- WREG32_SMC(ixCG_THERMAL_CTRL, tmp);
-#endif
-
- adev->pm.dpm.thermal.min_temp = low_temp;
- adev->pm.dpm.thermal.max_temp = high_temp;
- return 0;
-}
-
-static int ci_thermal_enable_alert(struct amdgpu_device *adev,
- bool enable)
-{
- u32 thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- PPSMC_Result result;
-
- if (enable) {
- thermal_int &= ~(CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK |
- CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK);
- WREG32_SMC(ixCG_THERMAL_INT, thermal_int);
- result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Thermal_Cntl_Enable);
- if (result != PPSMC_Result_OK) {
- DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
- return -EINVAL;
- }
- } else {
- thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK |
- CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
- WREG32_SMC(ixCG_THERMAL_INT, thermal_int);
- result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Thermal_Cntl_Disable);
- if (result != PPSMC_Result_OK) {
- DRM_DEBUG_KMS("Could not disable thermal interrupts.\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static void ci_fan_ctrl_set_static_mode(struct amdgpu_device *adev, u32 mode)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
-
- if (pi->fan_ctrl_is_in_default_mode) {
- tmp = (RREG32_SMC(ixCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK)
- >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
- pi->fan_ctrl_default_mode = tmp;
- tmp = (RREG32_SMC(ixCG_FDO_CTRL2) & CG_FDO_CTRL2__TMIN_MASK)
- >> CG_FDO_CTRL2__TMIN__SHIFT;
- pi->t_min = tmp;
- pi->fan_ctrl_is_in_default_mode = false;
- }
-
- tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
- tmp |= 0 << CG_FDO_CTRL2__TMIN__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL2, tmp);
-
- tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
- tmp |= mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL2, tmp);
-}
-
-static int ci_thermal_setup_fan_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
- u32 duty100;
- u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
- u16 fdo_min, slope1, slope2;
- u32 reference_clock, tmp;
- int ret;
- u64 tmp64;
-
- if (!pi->fan_table_start) {
- adev->pm.dpm.fan.ucode_fan_control = false;
- return 0;
- }
-
- duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
- >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
-
- if (duty100 == 0) {
- adev->pm.dpm.fan.ucode_fan_control = false;
- return 0;
- }
-
- tmp64 = (u64)adev->pm.dpm.fan.pwm_min * duty100;
- do_div(tmp64, 10000);
- fdo_min = (u16)tmp64;
-
- t_diff1 = adev->pm.dpm.fan.t_med - adev->pm.dpm.fan.t_min;
- t_diff2 = adev->pm.dpm.fan.t_high - adev->pm.dpm.fan.t_med;
-
- pwm_diff1 = adev->pm.dpm.fan.pwm_med - adev->pm.dpm.fan.pwm_min;
- pwm_diff2 = adev->pm.dpm.fan.pwm_high - adev->pm.dpm.fan.pwm_med;
-
- slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
- slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
-
- fan_table.TempMin = cpu_to_be16((50 + adev->pm.dpm.fan.t_min) / 100);
- fan_table.TempMed = cpu_to_be16((50 + adev->pm.dpm.fan.t_med) / 100);
- fan_table.TempMax = cpu_to_be16((50 + adev->pm.dpm.fan.t_max) / 100);
-
- fan_table.Slope1 = cpu_to_be16(slope1);
- fan_table.Slope2 = cpu_to_be16(slope2);
-
- fan_table.FdoMin = cpu_to_be16(fdo_min);
-
- fan_table.HystDown = cpu_to_be16(adev->pm.dpm.fan.t_hyst);
-
- fan_table.HystUp = cpu_to_be16(1);
-
- fan_table.HystSlope = cpu_to_be16(1);
-
- fan_table.TempRespLim = cpu_to_be16(5);
-
- reference_clock = amdgpu_asic_get_xclk(adev);
-
- fan_table.RefreshPeriod = cpu_to_be32((adev->pm.dpm.fan.cycle_delay *
- reference_clock) / 1600);
-
- fan_table.FdoMax = cpu_to_be16((u16)duty100);
-
- tmp = (RREG32_SMC(ixCG_MULT_THERMAL_CTRL) & CG_MULT_THERMAL_CTRL__TEMP_SEL_MASK)
- >> CG_MULT_THERMAL_CTRL__TEMP_SEL__SHIFT;
- fan_table.TempSrc = (uint8_t)tmp;
-
- ret = amdgpu_ci_copy_bytes_to_smc(adev,
- pi->fan_table_start,
- (u8 *)(&fan_table),
- sizeof(fan_table),
- pi->sram_end);
-
- if (ret) {
- DRM_ERROR("Failed to load fan table to the SMC.");
- adev->pm.dpm.fan.ucode_fan_control = false;
- }
-
- return 0;
-}
-
-static int ci_fan_ctrl_start_smc_fan_control(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result ret;
-
- if (pi->caps_od_fuzzy_fan_control_support) {
- ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_StartFanControl,
- FAN_CONTROL_FUZZY);
- if (ret != PPSMC_Result_OK)
- return -EINVAL;
- ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetFanPwmMax,
- adev->pm.dpm.fan.default_max_fan_pwm);
- if (ret != PPSMC_Result_OK)
- return -EINVAL;
- } else {
- ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_StartFanControl,
- FAN_CONTROL_TABLE);
- if (ret != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- pi->fan_is_controlled_by_smc = true;
- return 0;
-}
-
-
-static int ci_fan_ctrl_stop_smc_fan_control(struct amdgpu_device *adev)
-{
- PPSMC_Result ret;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- ret = amdgpu_ci_send_msg_to_smc(adev, PPSMC_StopFanControl);
- if (ret == PPSMC_Result_OK) {
- pi->fan_is_controlled_by_smc = false;
- return 0;
- } else {
- return -EINVAL;
- }
-}
-
-static int ci_dpm_get_fan_speed_percent(void *handle,
- u32 *speed)
-{
- u32 duty, duty100;
- u64 tmp64;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->pm.no_fan)
- return -ENOENT;
-
- duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
- >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
- duty = (RREG32_SMC(ixCG_THERMAL_STATUS) & CG_THERMAL_STATUS__FDO_PWM_DUTY_MASK)
- >> CG_THERMAL_STATUS__FDO_PWM_DUTY__SHIFT;
-
- if (duty100 == 0)
- return -EINVAL;
-
- tmp64 = (u64)duty * 100;
- do_div(tmp64, duty100);
- *speed = (u32)tmp64;
-
- if (*speed > 100)
- *speed = 100;
-
- return 0;
-}
-
-static int ci_dpm_set_fan_speed_percent(void *handle,
- u32 speed)
-{
- u32 tmp;
- u32 duty, duty100;
- u64 tmp64;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (adev->pm.no_fan)
- return -ENOENT;
-
- if (pi->fan_is_controlled_by_smc)
- return -EINVAL;
-
- if (speed > 100)
- return -EINVAL;
-
- duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
- >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
-
- if (duty100 == 0)
- return -EINVAL;
-
- tmp64 = (u64)speed * duty100;
- do_div(tmp64, 100);
- duty = (u32)tmp64;
-
- tmp = RREG32_SMC(ixCG_FDO_CTRL0) & ~CG_FDO_CTRL0__FDO_STATIC_DUTY_MASK;
- tmp |= duty << CG_FDO_CTRL0__FDO_STATIC_DUTY__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL0, tmp);
-
- return 0;
-}
-
-static void ci_dpm_set_fan_control_mode(void *handle, u32 mode)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- switch (mode) {
- case AMD_FAN_CTRL_NONE:
- if (adev->pm.dpm.fan.ucode_fan_control)
- ci_fan_ctrl_stop_smc_fan_control(adev);
- ci_dpm_set_fan_speed_percent(adev, 100);
- break;
- case AMD_FAN_CTRL_MANUAL:
- if (adev->pm.dpm.fan.ucode_fan_control)
- ci_fan_ctrl_stop_smc_fan_control(adev);
- break;
- case AMD_FAN_CTRL_AUTO:
- if (adev->pm.dpm.fan.ucode_fan_control)
- ci_thermal_start_smc_fan_control(adev);
- break;
- default:
- break;
- }
-}
-
-static u32 ci_dpm_get_fan_control_mode(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (pi->fan_is_controlled_by_smc)
- return AMD_FAN_CTRL_AUTO;
- else
- return AMD_FAN_CTRL_MANUAL;
-}
-
-#if 0
-static int ci_fan_ctrl_get_fan_speed_rpm(struct amdgpu_device *adev,
- u32 *speed)
-{
- u32 tach_period;
- u32 xclk = amdgpu_asic_get_xclk(adev);
-
- if (adev->pm.no_fan)
- return -ENOENT;
-
- if (adev->pm.fan_pulses_per_revolution == 0)
- return -ENOENT;
-
- tach_period = (RREG32_SMC(ixCG_TACH_STATUS) & CG_TACH_STATUS__TACH_PERIOD_MASK)
- >> CG_TACH_STATUS__TACH_PERIOD__SHIFT;
- if (tach_period == 0)
- return -ENOENT;
-
- *speed = 60 * xclk * 10000 / tach_period;
-
- return 0;
-}
-
-static int ci_fan_ctrl_set_fan_speed_rpm(struct amdgpu_device *adev,
- u32 speed)
-{
- u32 tach_period, tmp;
- u32 xclk = amdgpu_asic_get_xclk(adev);
-
- if (adev->pm.no_fan)
- return -ENOENT;
-
- if (adev->pm.fan_pulses_per_revolution == 0)
- return -ENOENT;
-
- if ((speed < adev->pm.fan_min_rpm) ||
- (speed > adev->pm.fan_max_rpm))
- return -EINVAL;
-
- if (adev->pm.dpm.fan.ucode_fan_control)
- ci_fan_ctrl_stop_smc_fan_control(adev);
-
- tach_period = 60 * xclk * 10000 / (8 * speed);
- tmp = RREG32_SMC(ixCG_TACH_CTRL) & ~CG_TACH_CTRL__TARGET_PERIOD_MASK;
- tmp |= tach_period << CG_TACH_CTRL__TARGET_PERIOD__SHIFT;
- WREG32_SMC(CG_TACH_CTRL, tmp);
-
- ci_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC_RPM);
-
- return 0;
-}
-#endif
-
-static void ci_fan_ctrl_set_default_mode(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
-
- if (!pi->fan_ctrl_is_in_default_mode) {
- tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
- tmp |= pi->fan_ctrl_default_mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL2, tmp);
-
- tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
- tmp |= pi->t_min << CG_FDO_CTRL2__TMIN__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL2, tmp);
- pi->fan_ctrl_is_in_default_mode = true;
- }
-}
-
-static void ci_thermal_start_smc_fan_control(struct amdgpu_device *adev)
-{
- if (adev->pm.dpm.fan.ucode_fan_control) {
- ci_fan_ctrl_start_smc_fan_control(adev);
- ci_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC);
- }
-}
-
-static void ci_thermal_initialize(struct amdgpu_device *adev)
-{
- u32 tmp;
-
- if (adev->pm.fan_pulses_per_revolution) {
- tmp = RREG32_SMC(ixCG_TACH_CTRL) & ~CG_TACH_CTRL__EDGE_PER_REV_MASK;
- tmp |= (adev->pm.fan_pulses_per_revolution - 1)
- << CG_TACH_CTRL__EDGE_PER_REV__SHIFT;
- WREG32_SMC(ixCG_TACH_CTRL, tmp);
- }
-
- tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TACH_PWM_RESP_RATE_MASK;
- tmp |= 0x28 << CG_FDO_CTRL2__TACH_PWM_RESP_RATE__SHIFT;
- WREG32_SMC(ixCG_FDO_CTRL2, tmp);
-}
-
-static int ci_thermal_start_thermal_controller(struct amdgpu_device *adev)
-{
- int ret;
-
- ci_thermal_initialize(adev);
- ret = ci_thermal_set_temperature_range(adev, CISLANDS_TEMP_RANGE_MIN, CISLANDS_TEMP_RANGE_MAX);
- if (ret)
- return ret;
- ret = ci_thermal_enable_alert(adev, true);
- if (ret)
- return ret;
- if (adev->pm.dpm.fan.ucode_fan_control) {
- ret = ci_thermal_setup_fan_table(adev);
- if (ret)
- return ret;
- ci_thermal_start_smc_fan_control(adev);
- }
-
- return 0;
-}
-
-static void ci_thermal_stop_thermal_controller(struct amdgpu_device *adev)
-{
- if (!adev->pm.no_fan)
- ci_fan_ctrl_set_default_mode(adev);
-}
-
-static int ci_read_smc_soft_register(struct amdgpu_device *adev,
- u16 reg_offset, u32 *value)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- return amdgpu_ci_read_smc_sram_dword(adev,
- pi->soft_regs_start + reg_offset,
- value, pi->sram_end);
-}
-
-static int ci_write_smc_soft_register(struct amdgpu_device *adev,
- u16 reg_offset, u32 value)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- return amdgpu_ci_write_smc_sram_dword(adev,
- pi->soft_regs_start + reg_offset,
- value, pi->sram_end);
-}
-
-static void ci_init_fps_limits(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
-
- if (pi->caps_fps) {
- u16 tmp;
-
- tmp = 45;
- table->FpsHighT = cpu_to_be16(tmp);
-
- tmp = 30;
- table->FpsLowT = cpu_to_be16(tmp);
- }
-}
-
-static int ci_update_sclk_t(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret = 0;
- u32 low_sclk_interrupt_t = 0;
-
- if (pi->caps_sclk_throttle_low_notification) {
- low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t);
-
- ret = amdgpu_ci_copy_bytes_to_smc(adev,
- pi->dpm_table_start +
- offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT),
- (u8 *)&low_sclk_interrupt_t,
- sizeof(u32), pi->sram_end);
-
- }
-
- return ret;
-}
-
-static void ci_get_leakage_voltages(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u16 leakage_id, virtual_voltage_id;
- u16 vddc, vddci;
- int i;
-
- pi->vddc_leakage.count = 0;
- pi->vddci_leakage.count = 0;
-
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
- for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
- virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
- if (amdgpu_atombios_get_voltage_evv(adev, virtual_voltage_id, &vddc) != 0)
- continue;
- if (vddc != 0 && vddc != virtual_voltage_id) {
- pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
- pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
- pi->vddc_leakage.count++;
- }
- }
- } else if (amdgpu_atombios_get_leakage_id_from_vbios(adev, &leakage_id) == 0) {
- for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
- virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
- if (amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(adev, &vddc, &vddci,
- virtual_voltage_id,
- leakage_id) == 0) {
- if (vddc != 0 && vddc != virtual_voltage_id) {
- pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
- pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
- pi->vddc_leakage.count++;
- }
- if (vddci != 0 && vddci != virtual_voltage_id) {
- pi->vddci_leakage.actual_voltage[pi->vddci_leakage.count] = vddci;
- pi->vddci_leakage.leakage_id[pi->vddci_leakage.count] = virtual_voltage_id;
- pi->vddci_leakage.count++;
- }
- }
- }
- }
-}
-
-static void ci_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- bool want_thermal_protection;
- enum amdgpu_dpm_event_src dpm_event_src;
- u32 tmp;
-
- switch (sources) {
- case 0:
- default:
- want_thermal_protection = false;
- break;
- case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL):
- want_thermal_protection = true;
- dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGITAL;
- break;
- case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
- want_thermal_protection = true;
- dpm_event_src = AMDGPU_DPM_EVENT_SRC_EXTERNAL;
- break;
- case ((1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
- (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL)):
- want_thermal_protection = true;
- dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
- break;
- }
-
- if (want_thermal_protection) {
-#if 0
- /* XXX: need to figure out how to handle this properly */
- tmp = RREG32_SMC(ixCG_THERMAL_CTRL);
- tmp &= DPM_EVENT_SRC_MASK;
- tmp |= DPM_EVENT_SRC(dpm_event_src);
- WREG32_SMC(ixCG_THERMAL_CTRL, tmp);
-#endif
-
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- if (pi->thermal_protection)
- tmp &= ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
- else
- tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
- } else {
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
- }
-}
-
-static void ci_enable_auto_throttle_source(struct amdgpu_device *adev,
- enum amdgpu_dpm_auto_throttle_src source,
- bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (enable) {
- if (!(pi->active_auto_throttle_sources & (1 << source))) {
- pi->active_auto_throttle_sources |= 1 << source;
- ci_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
- }
- } else {
- if (pi->active_auto_throttle_sources & (1 << source)) {
- pi->active_auto_throttle_sources &= ~(1 << source);
- ci_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
- }
- }
-}
-
-static void ci_enable_vr_hot_gpio_interrupt(struct amdgpu_device *adev)
-{
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableVRHotGPIOInterrupt);
-}
-
-static int ci_unfreeze_sclk_mclk_dpm(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
-
- if (!pi->need_update_smu7_dpm_table)
- return 0;
-
- if ((!pi->sclk_dpm_key_disabled) &&
- (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- if ((!pi->mclk_dpm_key_disabled) &&
- (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- pi->need_update_smu7_dpm_table = 0;
- return 0;
-}
-
-static int ci_enable_sclk_mclk_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
-
- if (enable) {
- if (!pi->sclk_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DPM_Enable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- if (!pi->mclk_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_Enable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
-
- WREG32_P(mmMC_SEQ_CNTL_3, MC_SEQ_CNTL_3__CAC_EN_MASK,
- ~MC_SEQ_CNTL_3__CAC_EN_MASK);
-
- WREG32_SMC(ixLCAC_MC0_CNTL, 0x05);
- WREG32_SMC(ixLCAC_MC1_CNTL, 0x05);
- WREG32_SMC(ixLCAC_CPL_CNTL, 0x100005);
-
- udelay(10);
-
- WREG32_SMC(ixLCAC_MC0_CNTL, 0x400005);
- WREG32_SMC(ixLCAC_MC1_CNTL, 0x400005);
- WREG32_SMC(ixLCAC_CPL_CNTL, 0x500005);
- }
- } else {
- if (!pi->sclk_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DPM_Disable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- if (!pi->mclk_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_Disable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int ci_start_dpm(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
- int ret;
- u32 tmp;
-
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- tmp |= GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
-
- tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
- tmp |= SCLK_PWRMGT_CNTL__DYNAMIC_PM_EN_MASK;
- WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
-
- ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, VoltageChangeTimeout), 0x1000);
-
- WREG32_P(mmBIF_LNCNT_RESET, 0, ~BIF_LNCNT_RESET__RESET_LNCNT_EN_MASK);
-
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Voltage_Cntl_Enable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
-
- ret = ci_enable_sclk_mclk_dpm(adev, true);
- if (ret)
- return ret;
-
- if (!pi->pcie_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_Enable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_freeze_sclk_mclk_dpm(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
-
- if (!pi->need_update_smu7_dpm_table)
- return 0;
-
- if ((!pi->sclk_dpm_key_disabled) &&
- (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_SCLKDPM_FreezeLevel);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- if ((!pi->mclk_dpm_key_disabled) &&
- (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_FreezeLevel);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_stop_dpm(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result smc_result;
- int ret;
- u32 tmp;
-
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- tmp &= ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
-
- tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
- tmp &= ~SCLK_PWRMGT_CNTL__DYNAMIC_PM_EN_MASK;
- WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
-
- if (!pi->pcie_dpm_key_disabled) {
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_Disable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- ret = ci_enable_sclk_mclk_dpm(adev, false);
- if (ret)
- return ret;
-
- smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Voltage_Cntl_Disable);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
-
- return 0;
-}
-
-static void ci_enable_sclk_control(struct amdgpu_device *adev, bool enable)
-{
- u32 tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
-
- if (enable)
- tmp &= ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK;
- else
- tmp |= SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK;
- WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
-}
-
-#if 0
-static int ci_notify_hw_of_power_source(struct amdgpu_device *adev,
- bool ac_power)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_cac_tdp_table *cac_tdp_table =
- adev->pm.dpm.dyn_state.cac_tdp_table;
- u32 power_limit;
-
- if (ac_power)
- power_limit = (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
- else
- power_limit = (u32)(cac_tdp_table->battery_power_limit * 256);
-
- ci_set_power_limit(adev, power_limit);
-
- if (pi->caps_automatic_dc_transition) {
- if (ac_power)
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
- else
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Remove_DC_Clamp);
- }
-
- return 0;
-}
-#endif
-
-static PPSMC_Result amdgpu_ci_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
- PPSMC_Msg msg, u32 parameter)
-{
- WREG32(mmSMC_MSG_ARG_0, parameter);
- return amdgpu_ci_send_msg_to_smc(adev, msg);
-}
-
-static PPSMC_Result amdgpu_ci_send_msg_to_smc_return_parameter(struct amdgpu_device *adev,
- PPSMC_Msg msg, u32 *parameter)
-{
- PPSMC_Result smc_result;
-
- smc_result = amdgpu_ci_send_msg_to_smc(adev, msg);
-
- if ((smc_result == PPSMC_Result_OK) && parameter)
- *parameter = RREG32(mmSMC_MSG_ARG_0);
-
- return smc_result;
-}
-
-static int ci_dpm_force_state_sclk(struct amdgpu_device *adev, u32 n)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (!pi->sclk_dpm_key_disabled) {
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_dpm_force_state_mclk(struct amdgpu_device *adev, u32 n)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (!pi->mclk_dpm_key_disabled) {
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_dpm_force_state_pcie(struct amdgpu_device *adev, u32 n)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (!pi->pcie_dpm_key_disabled) {
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_PCIeDPM_ForceLevel, n);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_set_power_limit(struct amdgpu_device *adev, u32 n)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_PkgPwrSetLimit, n);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_set_overdrive_target_tdp(struct amdgpu_device *adev,
- u32 target_tdp)
-{
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- return 0;
-}
-
-#if 0
-static int ci_set_boot_state(struct amdgpu_device *adev)
-{
- return ci_enable_sclk_mclk_dpm(adev, false);
-}
-#endif
-
-static u32 ci_get_average_sclk_freq(struct amdgpu_device *adev)
-{
- u32 sclk_freq;
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_return_parameter(adev,
- PPSMC_MSG_API_GetSclkFrequency,
- &sclk_freq);
- if (smc_result != PPSMC_Result_OK)
- sclk_freq = 0;
-
- return sclk_freq;
-}
-
-static u32 ci_get_average_mclk_freq(struct amdgpu_device *adev)
-{
- u32 mclk_freq;
- PPSMC_Result smc_result =
- amdgpu_ci_send_msg_to_smc_return_parameter(adev,
- PPSMC_MSG_API_GetMclkFrequency,
- &mclk_freq);
- if (smc_result != PPSMC_Result_OK)
- mclk_freq = 0;
-
- return mclk_freq;
-}
-
-static void ci_dpm_start_smc(struct amdgpu_device *adev)
-{
- int i;
-
- amdgpu_ci_program_jump_on_start(adev);
- amdgpu_ci_start_smc_clock(adev);
- amdgpu_ci_start_smc(adev);
- for (i = 0; i < adev->usec_timeout; i++) {
- if (RREG32_SMC(ixFIRMWARE_FLAGS) & FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK)
- break;
- }
-}
-
-static void ci_dpm_stop_smc(struct amdgpu_device *adev)
-{
- amdgpu_ci_reset_smc(adev);
- amdgpu_ci_stop_smc_clock(adev);
-}
-
-static int ci_process_firmware_header(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
- int ret;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, DpmTable),
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- pi->dpm_table_start = tmp;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, SoftRegisters),
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- pi->soft_regs_start = tmp;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, mcRegisterTable),
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- pi->mc_reg_table_start = tmp;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, FanTable),
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- pi->fan_table_start = tmp;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev,
- SMU7_FIRMWARE_HEADER_LOCATION +
- offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- pi->arb_table_start = tmp;
-
- return 0;
-}
-
-static void ci_read_clock_registers(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- pi->clock_registers.cg_spll_func_cntl =
- RREG32_SMC(ixCG_SPLL_FUNC_CNTL);
- pi->clock_registers.cg_spll_func_cntl_2 =
- RREG32_SMC(ixCG_SPLL_FUNC_CNTL_2);
- pi->clock_registers.cg_spll_func_cntl_3 =
- RREG32_SMC(ixCG_SPLL_FUNC_CNTL_3);
- pi->clock_registers.cg_spll_func_cntl_4 =
- RREG32_SMC(ixCG_SPLL_FUNC_CNTL_4);
- pi->clock_registers.cg_spll_spread_spectrum =
- RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM);
- pi->clock_registers.cg_spll_spread_spectrum_2 =
- RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM_2);
- pi->clock_registers.dll_cntl = RREG32(mmDLL_CNTL);
- pi->clock_registers.mclk_pwrmgt_cntl = RREG32(mmMCLK_PWRMGT_CNTL);
- pi->clock_registers.mpll_ad_func_cntl = RREG32(mmMPLL_AD_FUNC_CNTL);
- pi->clock_registers.mpll_dq_func_cntl = RREG32(mmMPLL_DQ_FUNC_CNTL);
- pi->clock_registers.mpll_func_cntl = RREG32(mmMPLL_FUNC_CNTL);
- pi->clock_registers.mpll_func_cntl_1 = RREG32(mmMPLL_FUNC_CNTL_1);
- pi->clock_registers.mpll_func_cntl_2 = RREG32(mmMPLL_FUNC_CNTL_2);
- pi->clock_registers.mpll_ss1 = RREG32(mmMPLL_SS1);
- pi->clock_registers.mpll_ss2 = RREG32(mmMPLL_SS2);
-}
-
-static void ci_init_sclk_t(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- pi->low_sclk_interrupt_t = 0;
-}
-
-static void ci_enable_thermal_protection(struct amdgpu_device *adev,
- bool enable)
-{
- u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
-
- if (enable)
- tmp &= ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
- else
- tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
-}
-
-static void ci_enable_acpi_power_management(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
-
- tmp |= GENERAL_PWRMGT__STATIC_PM_EN_MASK;
-
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
-}
-
-#if 0
-static int ci_enter_ulp_state(struct amdgpu_device *adev)
-{
-
- WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
-
- udelay(25000);
-
- return 0;
-}
-
-static int ci_exit_ulp_state(struct amdgpu_device *adev)
-{
- int i;
-
- WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
-
- udelay(7000);
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if (RREG32(mmSMC_RESP_0) == 1)
- break;
- udelay(1000);
- }
-
- return 0;
-}
-#endif
-
-static int ci_notify_smc_display_change(struct amdgpu_device *adev,
- bool has_display)
-{
- PPSMC_Msg msg = has_display ? PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
-
- return (amdgpu_ci_send_msg_to_smc(adev, msg) == PPSMC_Result_OK) ? 0 : -EINVAL;
-}
-
-static int ci_enable_ds_master_switch(struct amdgpu_device *adev,
- bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (enable) {
- if (pi->caps_sclk_ds) {
- if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_ON) != PPSMC_Result_OK)
- return -EINVAL;
- } else {
- if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
- return -EINVAL;
- }
- } else {
- if (pi->caps_sclk_ds) {
- if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static void ci_program_display_gap(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixCG_DISPLAY_GAP_CNTL);
- u32 pre_vbi_time_in_us;
- u32 frame_time_in_us;
- u32 ref_clock = adev->clock.spll.reference_freq;
- u32 refresh_rate = amdgpu_dpm_get_vrefresh(adev);
- u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
-
- tmp &= ~CG_DISPLAY_GAP_CNTL__DISP_GAP_MASK;
- if (adev->pm.dpm.new_active_crtc_count > 0)
- tmp |= (AMDGPU_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT);
- else
- tmp |= (AMDGPU_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT);
- WREG32_SMC(ixCG_DISPLAY_GAP_CNTL, tmp);
-
- if (refresh_rate == 0)
- refresh_rate = 60;
- if (vblank_time == 0xffffffff)
- vblank_time = 500;
- frame_time_in_us = 1000000 / refresh_rate;
- pre_vbi_time_in_us =
- frame_time_in_us - 200 - vblank_time;
- tmp = pre_vbi_time_in_us * (ref_clock / 100);
-
- WREG32_SMC(ixCG_DISPLAY_GAP_CNTL2, tmp);
- ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, PreVBlankGap), 0x64);
- ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
-
-
- ci_notify_smc_display_change(adev, (adev->pm.dpm.new_active_crtc_count == 1));
-
-}
-
-static void ci_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
-
- if (enable) {
- if (pi->caps_sclk_ss_support) {
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- tmp |= GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
- }
- } else {
- tmp = RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM);
- tmp &= ~CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK;
- WREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM, tmp);
-
- tmp = RREG32_SMC(ixGENERAL_PWRMGT);
- tmp &= ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
- }
-}
-
-static void ci_program_sstp(struct amdgpu_device *adev)
-{
- WREG32_SMC(ixCG_STATIC_SCREEN_PARAMETER,
- ((CISLANDS_SSTU_DFLT << CG_STATIC_SCREEN_PARAMETER__STATIC_SCREEN_THRESHOLD_UNIT__SHIFT) |
- (CISLANDS_SST_DFLT << CG_STATIC_SCREEN_PARAMETER__STATIC_SCREEN_THRESHOLD__SHIFT)));
-}
-
-static void ci_enable_display_gap(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixCG_DISPLAY_GAP_CNTL);
-
- tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP_GAP_MASK |
- CG_DISPLAY_GAP_CNTL__DISP_GAP_MCHG_MASK);
- tmp |= ((AMDGPU_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT) |
- (AMDGPU_PM_DISPLAY_GAP_VBLANK << CG_DISPLAY_GAP_CNTL__DISP_GAP_MCHG__SHIFT));
-
- WREG32_SMC(ixCG_DISPLAY_GAP_CNTL, tmp);
-}
-
-static void ci_program_vc(struct amdgpu_device *adev)
-{
- u32 tmp;
-
- tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
- tmp &= ~(SCLK_PWRMGT_CNTL__RESET_SCLK_CNT_MASK | SCLK_PWRMGT_CNTL__RESET_BUSY_CNT_MASK);
- WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
-
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, CISLANDS_VRC_DFLT0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_1, CISLANDS_VRC_DFLT1);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_2, CISLANDS_VRC_DFLT2);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_3, CISLANDS_VRC_DFLT3);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_4, CISLANDS_VRC_DFLT4);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_5, CISLANDS_VRC_DFLT5);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_6, CISLANDS_VRC_DFLT6);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_7, CISLANDS_VRC_DFLT7);
-}
-
-static void ci_clear_vc(struct amdgpu_device *adev)
-{
- u32 tmp;
-
- tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
- tmp |= (SCLK_PWRMGT_CNTL__RESET_SCLK_CNT_MASK | SCLK_PWRMGT_CNTL__RESET_BUSY_CNT_MASK);
- WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
-
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_1, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_2, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_3, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_4, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_5, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_6, 0);
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_7, 0);
-}
-
-static int ci_upload_firmware(struct amdgpu_device *adev)
-{
- int i, ret;
-
- if (amdgpu_ci_is_smc_running(adev)) {
- DRM_INFO("smc is running, no need to load smc firmware\n");
- return 0;
- }
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if (RREG32_SMC(ixRCU_UC_EVENTS) & RCU_UC_EVENTS__boot_seq_done_MASK)
- break;
- }
- WREG32_SMC(ixSMC_SYSCON_MISC_CNTL, 1);
-
- amdgpu_ci_stop_smc_clock(adev);
- amdgpu_ci_reset_smc(adev);
-
- ret = amdgpu_ci_load_smc_ucode(adev, SMC_RAM_END);
-
- return ret;
-
-}
-
-static int ci_get_svi2_voltage_table(struct amdgpu_device *adev,
- struct amdgpu_clock_voltage_dependency_table *voltage_dependency_table,
- struct atom_voltage_table *voltage_table)
-{
- u32 i;
-
- if (voltage_dependency_table == NULL)
- return -EINVAL;
-
- voltage_table->mask_low = 0;
- voltage_table->phase_delay = 0;
-
- voltage_table->count = voltage_dependency_table->count;
- for (i = 0; i < voltage_table->count; i++) {
- voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
- voltage_table->entries[i].smio_low = 0;
- }
-
- return 0;
-}
-
-static int ci_construct_voltage_tables(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
-
- if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
- ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
- VOLTAGE_OBJ_GPIO_LUT,
- &pi->vddc_voltage_table);
- if (ret)
- return ret;
- } else if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
- ret = ci_get_svi2_voltage_table(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
- &pi->vddc_voltage_table);
- if (ret)
- return ret;
- }
-
- if (pi->vddc_voltage_table.count > SMU7_MAX_LEVELS_VDDC)
- ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_VDDC,
- &pi->vddc_voltage_table);
-
- if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
- ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDCI,
- VOLTAGE_OBJ_GPIO_LUT,
- &pi->vddci_voltage_table);
- if (ret)
- return ret;
- } else if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
- ret = ci_get_svi2_voltage_table(adev,
- &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
- &pi->vddci_voltage_table);
- if (ret)
- return ret;
- }
-
- if (pi->vddci_voltage_table.count > SMU7_MAX_LEVELS_VDDCI)
- ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_VDDCI,
- &pi->vddci_voltage_table);
-
- if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
- ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_MVDDC,
- VOLTAGE_OBJ_GPIO_LUT,
- &pi->mvdd_voltage_table);
- if (ret)
- return ret;
- } else if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
- ret = ci_get_svi2_voltage_table(adev,
- &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
- &pi->mvdd_voltage_table);
- if (ret)
- return ret;
- }
-
- if (pi->mvdd_voltage_table.count > SMU7_MAX_LEVELS_MVDD)
- ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_MVDD,
- &pi->mvdd_voltage_table);
-
- return 0;
-}
-
-static void ci_populate_smc_voltage_table(struct amdgpu_device *adev,
- struct atom_voltage_table_entry *voltage_table,
- SMU7_Discrete_VoltageLevel *smc_voltage_table)
-{
- int ret;
-
- ret = ci_get_std_voltage_value_sidd(adev, voltage_table,
- &smc_voltage_table->StdVoltageHiSidd,
- &smc_voltage_table->StdVoltageLoSidd);
-
- if (ret) {
- smc_voltage_table->StdVoltageHiSidd = voltage_table->value * VOLTAGE_SCALE;
- smc_voltage_table->StdVoltageLoSidd = voltage_table->value * VOLTAGE_SCALE;
- }
-
- smc_voltage_table->Voltage = cpu_to_be16(voltage_table->value * VOLTAGE_SCALE);
- smc_voltage_table->StdVoltageHiSidd =
- cpu_to_be16(smc_voltage_table->StdVoltageHiSidd);
- smc_voltage_table->StdVoltageLoSidd =
- cpu_to_be16(smc_voltage_table->StdVoltageLoSidd);
-}
-
-static int ci_populate_smc_vddc_table(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- unsigned int count;
-
- table->VddcLevelCount = pi->vddc_voltage_table.count;
- for (count = 0; count < table->VddcLevelCount; count++) {
- ci_populate_smc_voltage_table(adev,
- &pi->vddc_voltage_table.entries[count],
- &table->VddcLevel[count]);
-
- if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
- table->VddcLevel[count].Smio |=
- pi->vddc_voltage_table.entries[count].smio_low;
- else
- table->VddcLevel[count].Smio = 0;
- }
- table->VddcLevelCount = cpu_to_be32(table->VddcLevelCount);
-
- return 0;
-}
-
-static int ci_populate_smc_vddci_table(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- unsigned int count;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- table->VddciLevelCount = pi->vddci_voltage_table.count;
- for (count = 0; count < table->VddciLevelCount; count++) {
- ci_populate_smc_voltage_table(adev,
- &pi->vddci_voltage_table.entries[count],
- &table->VddciLevel[count]);
-
- if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
- table->VddciLevel[count].Smio |=
- pi->vddci_voltage_table.entries[count].smio_low;
- else
- table->VddciLevel[count].Smio = 0;
- }
- table->VddciLevelCount = cpu_to_be32(table->VddciLevelCount);
-
- return 0;
-}
-
-static int ci_populate_smc_mvdd_table(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- unsigned int count;
-
- table->MvddLevelCount = pi->mvdd_voltage_table.count;
- for (count = 0; count < table->MvddLevelCount; count++) {
- ci_populate_smc_voltage_table(adev,
- &pi->mvdd_voltage_table.entries[count],
- &table->MvddLevel[count]);
-
- if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
- table->MvddLevel[count].Smio |=
- pi->mvdd_voltage_table.entries[count].smio_low;
- else
- table->MvddLevel[count].Smio = 0;
- }
- table->MvddLevelCount = cpu_to_be32(table->MvddLevelCount);
-
- return 0;
-}
-
-static int ci_populate_smc_voltage_tables(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- int ret;
-
- ret = ci_populate_smc_vddc_table(adev, table);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_vddci_table(adev, table);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_mvdd_table(adev, table);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int ci_populate_mvdd_value(struct amdgpu_device *adev, u32 mclk,
- SMU7_Discrete_VoltageLevel *voltage)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 i = 0;
-
- if (pi->mvdd_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
- for (i = 0; i < adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count; i++) {
- if (mclk <= adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries[i].clk) {
- voltage->Voltage = pi->mvdd_voltage_table.entries[i].value;
- break;
- }
- }
-
- if (i >= adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count)
- return -EINVAL;
- }
-
- return -EINVAL;
-}
-
-static int ci_get_std_voltage_value_sidd(struct amdgpu_device *adev,
- struct atom_voltage_table_entry *voltage_table,
- u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd)
-{
- u16 v_index, idx;
- bool voltage_found = false;
- *std_voltage_hi_sidd = voltage_table->value * VOLTAGE_SCALE;
- *std_voltage_lo_sidd = voltage_table->value * VOLTAGE_SCALE;
-
- if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
- return -EINVAL;
-
- if (adev->pm.dpm.dyn_state.cac_leakage_table.entries) {
- for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
- if (voltage_table->value ==
- adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
- voltage_found = true;
- if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
- idx = v_index;
- else
- idx = adev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
- *std_voltage_lo_sidd =
- adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
- *std_voltage_hi_sidd =
- adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
- break;
- }
- }
-
- if (!voltage_found) {
- for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
- if (voltage_table->value <=
- adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
- voltage_found = true;
- if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
- idx = v_index;
- else
- idx = adev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
- *std_voltage_lo_sidd =
- adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
- *std_voltage_hi_sidd =
- adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
- break;
- }
- }
- }
- }
-
- return 0;
-}
-
-static void ci_populate_phase_value_based_on_sclk(struct amdgpu_device *adev,
- const struct amdgpu_phase_shedding_limits_table *limits,
- u32 sclk,
- u32 *phase_shedding)
-{
- unsigned int i;
-
- *phase_shedding = 1;
-
- for (i = 0; i < limits->count; i++) {
- if (sclk < limits->entries[i].sclk) {
- *phase_shedding = i;
- break;
- }
- }
-}
-
-static void ci_populate_phase_value_based_on_mclk(struct amdgpu_device *adev,
- const struct amdgpu_phase_shedding_limits_table *limits,
- u32 mclk,
- u32 *phase_shedding)
-{
- unsigned int i;
-
- *phase_shedding = 1;
-
- for (i = 0; i < limits->count; i++) {
- if (mclk < limits->entries[i].mclk) {
- *phase_shedding = i;
- break;
- }
- }
-}
-
-static int ci_init_arb_table_index(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
- int ret;
-
- ret = amdgpu_ci_read_smc_sram_dword(adev, pi->arb_table_start,
- &tmp, pi->sram_end);
- if (ret)
- return ret;
-
- tmp &= 0x00FFFFFF;
- tmp |= MC_CG_ARB_FREQ_F1 << 24;
-
- return amdgpu_ci_write_smc_sram_dword(adev, pi->arb_table_start,
- tmp, pi->sram_end);
-}
-
-static int ci_get_dependency_volt_by_clk(struct amdgpu_device *adev,
- struct amdgpu_clock_voltage_dependency_table *allowed_clock_voltage_table,
- u32 clock, u32 *voltage)
-{
- u32 i = 0;
-
- if (allowed_clock_voltage_table->count == 0)
- return -EINVAL;
-
- for (i = 0; i < allowed_clock_voltage_table->count; i++) {
- if (allowed_clock_voltage_table->entries[i].clk >= clock) {
- *voltage = allowed_clock_voltage_table->entries[i].v;
- return 0;
- }
- }
-
- *voltage = allowed_clock_voltage_table->entries[i-1].v;
-
- return 0;
-}
-
-static u8 ci_get_sleep_divider_id_from_clock(u32 sclk, u32 min_sclk_in_sr)
-{
- u32 i;
- u32 tmp;
- u32 min = max(min_sclk_in_sr, (u32)CISLAND_MINIMUM_ENGINE_CLOCK);
-
- if (sclk < min)
- return 0;
-
- for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
- tmp = sclk >> i;
- if (tmp >= min || i == 0)
- break;
- }
-
- return (u8)i;
-}
-
-static int ci_initial_switch_from_arb_f0_to_f1(struct amdgpu_device *adev)
-{
- return ci_copy_and_switch_arb_sets(adev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
-}
-
-static int ci_reset_to_default(struct amdgpu_device *adev)
-{
- return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
-}
-
-static int ci_force_switch_to_arb_f0(struct amdgpu_device *adev)
-{
- u32 tmp;
-
- tmp = (RREG32_SMC(ixSMC_SCRATCH9) & 0x0000ff00) >> 8;
-
- if (tmp == MC_CG_ARB_FREQ_F0)
- return 0;
-
- return ci_copy_and_switch_arb_sets(adev, tmp, MC_CG_ARB_FREQ_F0);
-}
-
-static void ci_register_patching_mc_arb(struct amdgpu_device *adev,
- const u32 engine_clock,
- const u32 memory_clock,
- u32 *dram_timimg2)
-{
- bool patch;
- u32 tmp, tmp2;
-
- tmp = RREG32(mmMC_SEQ_MISC0);
- patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
-
- if (patch &&
- ((adev->pdev->device == 0x67B0) ||
- (adev->pdev->device == 0x67B1))) {
- if ((memory_clock > 100000) && (memory_clock <= 125000)) {
- tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
- *dram_timimg2 &= ~0x00ff0000;
- *dram_timimg2 |= tmp2 << 16;
- } else if ((memory_clock > 125000) && (memory_clock <= 137500)) {
- tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff;
- *dram_timimg2 &= ~0x00ff0000;
- *dram_timimg2 |= tmp2 << 16;
- }
- }
-}
-
-static int ci_populate_memory_timing_parameters(struct amdgpu_device *adev,
- u32 sclk,
- u32 mclk,
- SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs)
-{
- u32 dram_timing;
- u32 dram_timing2;
- u32 burst_time;
-
- amdgpu_atombios_set_engine_dram_timings(adev, sclk, mclk);
-
- dram_timing = RREG32(mmMC_ARB_DRAM_TIMING);
- dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2);
- burst_time = RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE0_MASK;
-
- ci_register_patching_mc_arb(adev, sclk, mclk, &dram_timing2);
-
- arb_regs->McArbDramTiming = cpu_to_be32(dram_timing);
- arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2);
- arb_regs->McArbBurstTime = (u8)burst_time;
-
- return 0;
-}
-
-static int ci_do_program_memory_timing_parameters(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- SMU7_Discrete_MCArbDramTimingTable arb_regs;
- u32 i, j;
- int ret = 0;
-
- memset(&arb_regs, 0, sizeof(SMU7_Discrete_MCArbDramTimingTable));
-
- for (i = 0; i < pi->dpm_table.sclk_table.count; i++) {
- for (j = 0; j < pi->dpm_table.mclk_table.count; j++) {
- ret = ci_populate_memory_timing_parameters(adev,
- pi->dpm_table.sclk_table.dpm_levels[i].value,
- pi->dpm_table.mclk_table.dpm_levels[j].value,
- &arb_regs.entries[i][j]);
- if (ret)
- break;
- }
- }
-
- if (ret == 0)
- ret = amdgpu_ci_copy_bytes_to_smc(adev,
- pi->arb_table_start,
- (u8 *)&arb_regs,
- sizeof(SMU7_Discrete_MCArbDramTimingTable),
- pi->sram_end);
-
- return ret;
-}
-
-static int ci_program_memory_timing_parameters(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (pi->need_update_smu7_dpm_table == 0)
- return 0;
-
- return ci_do_program_memory_timing_parameters(adev);
-}
-
-static void ci_populate_smc_initial_state(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_boot_state)
-{
- struct ci_ps *boot_state = ci_get_ps(amdgpu_boot_state);
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 level = 0;
-
- for (level = 0; level < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; level++) {
- if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[level].clk >=
- boot_state->performance_levels[0].sclk) {
- pi->smc_state_table.GraphicsBootLevel = level;
- break;
- }
- }
-
- for (level = 0; level < adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.count; level++) {
- if (adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries[level].clk >=
- boot_state->performance_levels[0].mclk) {
- pi->smc_state_table.MemoryBootLevel = level;
- break;
- }
- }
-}
-
-static u32 ci_get_dpm_level_enable_mask_value(struct ci_single_dpm_table *dpm_table)
-{
- u32 i;
- u32 mask_value = 0;
-
- for (i = dpm_table->count; i > 0; i--) {
- mask_value = mask_value << 1;
- if (dpm_table->dpm_levels[i-1].enabled)
- mask_value |= 0x1;
- else
- mask_value &= 0xFFFFFFFE;
- }
-
- return mask_value;
-}
-
-static void ci_populate_smc_link_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_dpm_table *dpm_table = &pi->dpm_table;
- u32 i;
-
- for (i = 0; i < dpm_table->pcie_speed_table.count; i++) {
- table->LinkLevel[i].PcieGenSpeed =
- (u8)dpm_table->pcie_speed_table.dpm_levels[i].value;
- table->LinkLevel[i].PcieLaneCount =
- amdgpu_encode_pci_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
- table->LinkLevel[i].EnabledForActivity = 1;
- table->LinkLevel[i].DownT = cpu_to_be32(5);
- table->LinkLevel[i].UpT = cpu_to_be32(30);
- }
-
- pi->smc_state_table.LinkLevelCount = (u8)dpm_table->pcie_speed_table.count;
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
-}
-
-static int ci_populate_smc_uvd_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- u32 count;
- struct atom_clock_dividers dividers;
- int ret = -EINVAL;
-
- table->UvdLevelCount =
- adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count;
-
- for (count = 0; count < table->UvdLevelCount; count++) {
- table->UvdLevel[count].VclkFrequency =
- adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].vclk;
- table->UvdLevel[count].DclkFrequency =
- adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].dclk;
- table->UvdLevel[count].MinVddc =
- adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
- table->UvdLevel[count].MinVddcPhases = 1;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- table->UvdLevel[count].VclkFrequency, false, &dividers);
- if (ret)
- return ret;
-
- table->UvdLevel[count].VclkDivider = (u8)dividers.post_divider;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- table->UvdLevel[count].DclkFrequency, false, &dividers);
- if (ret)
- return ret;
-
- table->UvdLevel[count].DclkDivider = (u8)dividers.post_divider;
-
- table->UvdLevel[count].VclkFrequency = cpu_to_be32(table->UvdLevel[count].VclkFrequency);
- table->UvdLevel[count].DclkFrequency = cpu_to_be32(table->UvdLevel[count].DclkFrequency);
- table->UvdLevel[count].MinVddc = cpu_to_be16(table->UvdLevel[count].MinVddc);
- }
-
- return ret;
-}
-
-static int ci_populate_smc_vce_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- u32 count;
- struct atom_clock_dividers dividers;
- int ret = -EINVAL;
-
- table->VceLevelCount =
- adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count;
-
- for (count = 0; count < table->VceLevelCount; count++) {
- table->VceLevel[count].Frequency =
- adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].evclk;
- table->VceLevel[count].MinVoltage =
- (u16)adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
- table->VceLevel[count].MinPhases = 1;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- table->VceLevel[count].Frequency, false, &dividers);
- if (ret)
- return ret;
-
- table->VceLevel[count].Divider = (u8)dividers.post_divider;
-
- table->VceLevel[count].Frequency = cpu_to_be32(table->VceLevel[count].Frequency);
- table->VceLevel[count].MinVoltage = cpu_to_be16(table->VceLevel[count].MinVoltage);
- }
-
- return ret;
-
-}
-
-static int ci_populate_smc_acp_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- u32 count;
- struct atom_clock_dividers dividers;
- int ret = -EINVAL;
-
- table->AcpLevelCount = (u8)
- (adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count);
-
- for (count = 0; count < table->AcpLevelCount; count++) {
- table->AcpLevel[count].Frequency =
- adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].clk;
- table->AcpLevel[count].MinVoltage =
- adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].v;
- table->AcpLevel[count].MinPhases = 1;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- table->AcpLevel[count].Frequency, false, &dividers);
- if (ret)
- return ret;
-
- table->AcpLevel[count].Divider = (u8)dividers.post_divider;
-
- table->AcpLevel[count].Frequency = cpu_to_be32(table->AcpLevel[count].Frequency);
- table->AcpLevel[count].MinVoltage = cpu_to_be16(table->AcpLevel[count].MinVoltage);
- }
-
- return ret;
-}
-
-static int ci_populate_smc_samu_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- u32 count;
- struct atom_clock_dividers dividers;
- int ret = -EINVAL;
-
- table->SamuLevelCount =
- adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count;
-
- for (count = 0; count < table->SamuLevelCount; count++) {
- table->SamuLevel[count].Frequency =
- adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].clk;
- table->SamuLevel[count].MinVoltage =
- adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
- table->SamuLevel[count].MinPhases = 1;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- table->SamuLevel[count].Frequency, false, &dividers);
- if (ret)
- return ret;
-
- table->SamuLevel[count].Divider = (u8)dividers.post_divider;
-
- table->SamuLevel[count].Frequency = cpu_to_be32(table->SamuLevel[count].Frequency);
- table->SamuLevel[count].MinVoltage = cpu_to_be16(table->SamuLevel[count].MinVoltage);
- }
-
- return ret;
-}
-
-static int ci_calculate_mclk_params(struct amdgpu_device *adev,
- u32 memory_clock,
- SMU7_Discrete_MemoryLevel *mclk,
- bool strobe_mode,
- bool dll_state_on)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 dll_cntl = pi->clock_registers.dll_cntl;
- u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
- u32 mpll_ad_func_cntl = pi->clock_registers.mpll_ad_func_cntl;
- u32 mpll_dq_func_cntl = pi->clock_registers.mpll_dq_func_cntl;
- u32 mpll_func_cntl = pi->clock_registers.mpll_func_cntl;
- u32 mpll_func_cntl_1 = pi->clock_registers.mpll_func_cntl_1;
- u32 mpll_func_cntl_2 = pi->clock_registers.mpll_func_cntl_2;
- u32 mpll_ss1 = pi->clock_registers.mpll_ss1;
- u32 mpll_ss2 = pi->clock_registers.mpll_ss2;
- struct atom_mpll_param mpll_param;
- int ret;
-
- ret = amdgpu_atombios_get_memory_pll_dividers(adev, memory_clock, strobe_mode, &mpll_param);
- if (ret)
- return ret;
-
- mpll_func_cntl &= ~MPLL_FUNC_CNTL__BWCTRL_MASK;
- mpll_func_cntl |= (mpll_param.bwcntl << MPLL_FUNC_CNTL__BWCTRL__SHIFT);
-
- mpll_func_cntl_1 &= ~(MPLL_FUNC_CNTL_1__CLKF_MASK | MPLL_FUNC_CNTL_1__CLKFRAC_MASK |
- MPLL_FUNC_CNTL_1__VCO_MODE_MASK);
- mpll_func_cntl_1 |= (mpll_param.clkf) << MPLL_FUNC_CNTL_1__CLKF__SHIFT |
- (mpll_param.clkfrac << MPLL_FUNC_CNTL_1__CLKFRAC__SHIFT) |
- (mpll_param.vco_mode << MPLL_FUNC_CNTL_1__VCO_MODE__SHIFT);
-
- mpll_ad_func_cntl &= ~MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK;
- mpll_ad_func_cntl |= (mpll_param.post_div << MPLL_AD_FUNC_CNTL__YCLK_POST_DIV__SHIFT);
-
- if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
- mpll_dq_func_cntl &= ~(MPLL_DQ_FUNC_CNTL__YCLK_SEL_MASK |
- MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK);
- mpll_dq_func_cntl |= (mpll_param.yclk_sel << MPLL_DQ_FUNC_CNTL__YCLK_SEL__SHIFT) |
- (mpll_param.post_div << MPLL_AD_FUNC_CNTL__YCLK_POST_DIV__SHIFT);
- }
-
- if (pi->caps_mclk_ss_support) {
- struct amdgpu_atom_ss ss;
- u32 freq_nom;
- u32 tmp;
- u32 reference_clock = adev->clock.mpll.reference_freq;
-
- if (mpll_param.qdr == 1)
- freq_nom = memory_clock * 4 * (1 << mpll_param.post_div);
- else
- freq_nom = memory_clock * 2 * (1 << mpll_param.post_div);
-
- tmp = (freq_nom / reference_clock);
- tmp = tmp * tmp;
- if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
- ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
- u32 clks = reference_clock * 5 / ss.rate;
- u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom);
-
- mpll_ss1 &= ~MPLL_SS1__CLKV_MASK;
- mpll_ss1 |= (clkv << MPLL_SS1__CLKV__SHIFT);
-
- mpll_ss2 &= ~MPLL_SS2__CLKS_MASK;
- mpll_ss2 |= (clks << MPLL_SS2__CLKS__SHIFT);
- }
- }
-
- mclk_pwrmgt_cntl &= ~MCLK_PWRMGT_CNTL__DLL_SPEED_MASK;
- mclk_pwrmgt_cntl |= (mpll_param.dll_speed << MCLK_PWRMGT_CNTL__DLL_SPEED__SHIFT);
-
- if (dll_state_on)
- mclk_pwrmgt_cntl |= MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
- MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK;
- else
- mclk_pwrmgt_cntl &= ~(MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
- MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK);
-
- mclk->MclkFrequency = memory_clock;
- mclk->MpllFuncCntl = mpll_func_cntl;
- mclk->MpllFuncCntl_1 = mpll_func_cntl_1;
- mclk->MpllFuncCntl_2 = mpll_func_cntl_2;
- mclk->MpllAdFuncCntl = mpll_ad_func_cntl;
- mclk->MpllDqFuncCntl = mpll_dq_func_cntl;
- mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl;
- mclk->DllCntl = dll_cntl;
- mclk->MpllSs1 = mpll_ss1;
- mclk->MpllSs2 = mpll_ss2;
-
- return 0;
-}
-
-static int ci_populate_single_memory_level(struct amdgpu_device *adev,
- u32 memory_clock,
- SMU7_Discrete_MemoryLevel *memory_level)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
- bool dll_state_on;
-
- if (adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries) {
- ret = ci_get_dependency_volt_by_clk(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
- memory_clock, &memory_level->MinVddc);
- if (ret)
- return ret;
- }
-
- if (adev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries) {
- ret = ci_get_dependency_volt_by_clk(adev,
- &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
- memory_clock, &memory_level->MinVddci);
- if (ret)
- return ret;
- }
-
- if (adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries) {
- ret = ci_get_dependency_volt_by_clk(adev,
- &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
- memory_clock, &memory_level->MinMvdd);
- if (ret)
- return ret;
- }
-
- memory_level->MinVddcPhases = 1;
-
- if (pi->vddc_phase_shed_control)
- ci_populate_phase_value_based_on_mclk(adev,
- &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
- memory_clock,
- &memory_level->MinVddcPhases);
-
- memory_level->EnabledForActivity = 1;
- memory_level->EnabledForThrottle = 1;
- memory_level->UpH = 0;
- memory_level->DownH = 100;
- memory_level->VoltageDownH = 0;
- memory_level->ActivityLevel = (u16)pi->mclk_activity_target;
-
- memory_level->StutterEnable = false;
- memory_level->StrobeEnable = false;
- memory_level->EdcReadEnable = false;
- memory_level->EdcWriteEnable = false;
- memory_level->RttEnable = false;
-
- memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
- if (pi->mclk_stutter_mode_threshold &&
- (memory_clock <= pi->mclk_stutter_mode_threshold) &&
- (!pi->uvd_enabled) &&
- (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) &&
- (adev->pm.dpm.new_active_crtc_count <= 2))
- memory_level->StutterEnable = true;
-
- if (pi->mclk_strobe_mode_threshold &&
- (memory_clock <= pi->mclk_strobe_mode_threshold))
- memory_level->StrobeEnable = 1;
-
- if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
- memory_level->StrobeRatio =
- ci_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable);
- if (pi->mclk_edc_enable_threshold &&
- (memory_clock > pi->mclk_edc_enable_threshold))
- memory_level->EdcReadEnable = true;
-
- if (pi->mclk_edc_wr_enable_threshold &&
- (memory_clock > pi->mclk_edc_wr_enable_threshold))
- memory_level->EdcWriteEnable = true;
-
- if (memory_level->StrobeEnable) {
- if (ci_get_mclk_frequency_ratio(memory_clock, true) >=
- ((RREG32(mmMC_SEQ_MISC7) >> 16) & 0xf))
- dll_state_on = ((RREG32(mmMC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
- else
- dll_state_on = ((RREG32(mmMC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
- } else {
- dll_state_on = pi->dll_default_on;
- }
- } else {
- memory_level->StrobeRatio = ci_get_ddr3_mclk_frequency_ratio(memory_clock);
- dll_state_on = ((RREG32(mmMC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
- }
-
- ret = ci_calculate_mclk_params(adev, memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
- if (ret)
- return ret;
-
- memory_level->MinVddc = cpu_to_be32(memory_level->MinVddc * VOLTAGE_SCALE);
- memory_level->MinVddcPhases = cpu_to_be32(memory_level->MinVddcPhases);
- memory_level->MinVddci = cpu_to_be32(memory_level->MinVddci * VOLTAGE_SCALE);
- memory_level->MinMvdd = cpu_to_be32(memory_level->MinMvdd * VOLTAGE_SCALE);
-
- memory_level->MclkFrequency = cpu_to_be32(memory_level->MclkFrequency);
- memory_level->ActivityLevel = cpu_to_be16(memory_level->ActivityLevel);
- memory_level->MpllFuncCntl = cpu_to_be32(memory_level->MpllFuncCntl);
- memory_level->MpllFuncCntl_1 = cpu_to_be32(memory_level->MpllFuncCntl_1);
- memory_level->MpllFuncCntl_2 = cpu_to_be32(memory_level->MpllFuncCntl_2);
- memory_level->MpllAdFuncCntl = cpu_to_be32(memory_level->MpllAdFuncCntl);
- memory_level->MpllDqFuncCntl = cpu_to_be32(memory_level->MpllDqFuncCntl);
- memory_level->MclkPwrmgtCntl = cpu_to_be32(memory_level->MclkPwrmgtCntl);
- memory_level->DllCntl = cpu_to_be32(memory_level->DllCntl);
- memory_level->MpllSs1 = cpu_to_be32(memory_level->MpllSs1);
- memory_level->MpllSs2 = cpu_to_be32(memory_level->MpllSs2);
-
- return 0;
-}
-
-static int ci_populate_smc_acpi_level(struct amdgpu_device *adev,
- SMU7_Discrete_DpmTable *table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct atom_clock_dividers dividers;
- SMU7_Discrete_VoltageLevel voltage_level;
- u32 spll_func_cntl = pi->clock_registers.cg_spll_func_cntl;
- u32 spll_func_cntl_2 = pi->clock_registers.cg_spll_func_cntl_2;
- u32 dll_cntl = pi->clock_registers.dll_cntl;
- u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
- int ret;
-
- table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
-
- if (pi->acpi_vddc)
- table->ACPILevel.MinVddc = cpu_to_be32(pi->acpi_vddc * VOLTAGE_SCALE);
- else
- table->ACPILevel.MinVddc = cpu_to_be32(pi->min_vddc_in_pp_table * VOLTAGE_SCALE);
-
- table->ACPILevel.MinVddcPhases = pi->vddc_phase_shed_control ? 0 : 1;
-
- table->ACPILevel.SclkFrequency = adev->clock.spll.reference_freq;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
- table->ACPILevel.SclkFrequency, false, &dividers);
- if (ret)
- return ret;
-
- table->ACPILevel.SclkDid = (u8)dividers.post_divider;
- table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
- table->ACPILevel.DeepSleepDivId = 0;
-
- spll_func_cntl &= ~CG_SPLL_FUNC_CNTL__SPLL_PWRON_MASK;
- spll_func_cntl |= CG_SPLL_FUNC_CNTL__SPLL_RESET_MASK;
-
- spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK;
- spll_func_cntl_2 |= (4 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT);
-
- table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
- table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
- table->ACPILevel.CgSpllFuncCntl3 = pi->clock_registers.cg_spll_func_cntl_3;
- table->ACPILevel.CgSpllFuncCntl4 = pi->clock_registers.cg_spll_func_cntl_4;
- table->ACPILevel.SpllSpreadSpectrum = pi->clock_registers.cg_spll_spread_spectrum;
- table->ACPILevel.SpllSpreadSpectrum2 = pi->clock_registers.cg_spll_spread_spectrum_2;
- table->ACPILevel.CcPwrDynRm = 0;
- table->ACPILevel.CcPwrDynRm1 = 0;
-
- table->ACPILevel.Flags = cpu_to_be32(table->ACPILevel.Flags);
- table->ACPILevel.MinVddcPhases = cpu_to_be32(table->ACPILevel.MinVddcPhases);
- table->ACPILevel.SclkFrequency = cpu_to_be32(table->ACPILevel.SclkFrequency);
- table->ACPILevel.CgSpllFuncCntl = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl);
- table->ACPILevel.CgSpllFuncCntl2 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl2);
- table->ACPILevel.CgSpllFuncCntl3 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl3);
- table->ACPILevel.CgSpllFuncCntl4 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl4);
- table->ACPILevel.SpllSpreadSpectrum = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum);
- table->ACPILevel.SpllSpreadSpectrum2 = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum2);
- table->ACPILevel.CcPwrDynRm = cpu_to_be32(table->ACPILevel.CcPwrDynRm);
- table->ACPILevel.CcPwrDynRm1 = cpu_to_be32(table->ACPILevel.CcPwrDynRm1);
-
- table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
- table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
-
- if (pi->vddci_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
- if (pi->acpi_vddci)
- table->MemoryACPILevel.MinVddci =
- cpu_to_be32(pi->acpi_vddci * VOLTAGE_SCALE);
- else
- table->MemoryACPILevel.MinVddci =
- cpu_to_be32(pi->min_vddci_in_pp_table * VOLTAGE_SCALE);
- }
-
- if (ci_populate_mvdd_value(adev, 0, &voltage_level))
- table->MemoryACPILevel.MinMvdd = 0;
- else
- table->MemoryACPILevel.MinMvdd =
- cpu_to_be32(voltage_level.Voltage * VOLTAGE_SCALE);
-
- mclk_pwrmgt_cntl |= MCLK_PWRMGT_CNTL__MRDCK0_RESET_MASK |
- MCLK_PWRMGT_CNTL__MRDCK1_RESET_MASK;
- mclk_pwrmgt_cntl &= ~(MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
- MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK);
-
- dll_cntl &= ~(DLL_CNTL__MRDCK0_BYPASS_MASK | DLL_CNTL__MRDCK1_BYPASS_MASK);
-
- table->MemoryACPILevel.DllCntl = cpu_to_be32(dll_cntl);
- table->MemoryACPILevel.MclkPwrmgtCntl = cpu_to_be32(mclk_pwrmgt_cntl);
- table->MemoryACPILevel.MpllAdFuncCntl =
- cpu_to_be32(pi->clock_registers.mpll_ad_func_cntl);
- table->MemoryACPILevel.MpllDqFuncCntl =
- cpu_to_be32(pi->clock_registers.mpll_dq_func_cntl);
- table->MemoryACPILevel.MpllFuncCntl =
- cpu_to_be32(pi->clock_registers.mpll_func_cntl);
- table->MemoryACPILevel.MpllFuncCntl_1 =
- cpu_to_be32(pi->clock_registers.mpll_func_cntl_1);
- table->MemoryACPILevel.MpllFuncCntl_2 =
- cpu_to_be32(pi->clock_registers.mpll_func_cntl_2);
- table->MemoryACPILevel.MpllSs1 = cpu_to_be32(pi->clock_registers.mpll_ss1);
- table->MemoryACPILevel.MpllSs2 = cpu_to_be32(pi->clock_registers.mpll_ss2);
-
- table->MemoryACPILevel.EnabledForThrottle = 0;
- table->MemoryACPILevel.EnabledForActivity = 0;
- table->MemoryACPILevel.UpH = 0;
- table->MemoryACPILevel.DownH = 100;
- table->MemoryACPILevel.VoltageDownH = 0;
- table->MemoryACPILevel.ActivityLevel =
- cpu_to_be16((u16)pi->mclk_activity_target);
-
- table->MemoryACPILevel.StutterEnable = false;
- table->MemoryACPILevel.StrobeEnable = false;
- table->MemoryACPILevel.EdcReadEnable = false;
- table->MemoryACPILevel.EdcWriteEnable = false;
- table->MemoryACPILevel.RttEnable = false;
-
- return 0;
-}
-
-
-static int ci_enable_ulv(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ulv_parm *ulv = &pi->ulv;
-
- if (ulv->supported) {
- if (enable)
- return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
- else
- return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
- }
-
- return 0;
-}
-
-static int ci_populate_ulv_level(struct amdgpu_device *adev,
- SMU7_Discrete_Ulv *state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u16 ulv_voltage = adev->pm.dpm.backbias_response_time;
-
- state->CcPwrDynRm = 0;
- state->CcPwrDynRm1 = 0;
-
- if (ulv_voltage == 0) {
- pi->ulv.supported = false;
- return 0;
- }
-
- if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
- if (ulv_voltage > adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
- state->VddcOffset = 0;
- else
- state->VddcOffset =
- adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage;
- } else {
- if (ulv_voltage > adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
- state->VddcOffsetVid = 0;
- else
- state->VddcOffsetVid = (u8)
- ((adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage) *
- VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
- }
- state->VddcPhase = pi->vddc_phase_shed_control ? 0 : 1;
-
- state->CcPwrDynRm = cpu_to_be32(state->CcPwrDynRm);
- state->CcPwrDynRm1 = cpu_to_be32(state->CcPwrDynRm1);
- state->VddcOffset = cpu_to_be16(state->VddcOffset);
-
- return 0;
-}
-
-static int ci_calculate_sclk_params(struct amdgpu_device *adev,
- u32 engine_clock,
- SMU7_Discrete_GraphicsLevel *sclk)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct atom_clock_dividers dividers;
- u32 spll_func_cntl_3 = pi->clock_registers.cg_spll_func_cntl_3;
- u32 spll_func_cntl_4 = pi->clock_registers.cg_spll_func_cntl_4;
- u32 cg_spll_spread_spectrum = pi->clock_registers.cg_spll_spread_spectrum;
- u32 cg_spll_spread_spectrum_2 = pi->clock_registers.cg_spll_spread_spectrum_2;
- u32 reference_clock = adev->clock.spll.reference_freq;
- u32 reference_divider;
- u32 fbdiv;
- int ret;
-
- ret = amdgpu_atombios_get_clock_dividers(adev,
- COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
- engine_clock, false, &dividers);
- if (ret)
- return ret;
-
- reference_divider = 1 + dividers.ref_div;
- fbdiv = dividers.fb_div & 0x3FFFFFF;
-
- spll_func_cntl_3 &= ~CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK;
- spll_func_cntl_3 |= (fbdiv << CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT);
- spll_func_cntl_3 |= CG_SPLL_FUNC_CNTL_3__SPLL_DITHEN_MASK;
-
- if (pi->caps_sclk_ss_support) {
- struct amdgpu_atom_ss ss;
- u32 vco_freq = engine_clock * dividers.post_div;
-
- if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
- ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
- u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
- u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
-
- cg_spll_spread_spectrum &= ~(CG_SPLL_SPREAD_SPECTRUM__CLKS_MASK | CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK);
- cg_spll_spread_spectrum |= (clk_s << CG_SPLL_SPREAD_SPECTRUM__CLKS__SHIFT);
- cg_spll_spread_spectrum |= (1 << CG_SPLL_SPREAD_SPECTRUM__SSEN__SHIFT);
-
- cg_spll_spread_spectrum_2 &= ~CG_SPLL_SPREAD_SPECTRUM_2__CLKV_MASK;
- cg_spll_spread_spectrum_2 |= (clk_v << CG_SPLL_SPREAD_SPECTRUM_2__CLKV__SHIFT);
- }
- }
-
- sclk->SclkFrequency = engine_clock;
- sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
- sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
- sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
- sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2;
- sclk->SclkDid = (u8)dividers.post_divider;
-
- return 0;
-}
-
-static int ci_populate_single_graphic_level(struct amdgpu_device *adev,
- u32 engine_clock,
- u16 sclk_activity_level_t,
- SMU7_Discrete_GraphicsLevel *graphic_level)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
-
- ret = ci_calculate_sclk_params(adev, engine_clock, graphic_level);
- if (ret)
- return ret;
-
- ret = ci_get_dependency_volt_by_clk(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
- engine_clock, &graphic_level->MinVddc);
- if (ret)
- return ret;
-
- graphic_level->SclkFrequency = engine_clock;
-
- graphic_level->Flags = 0;
- graphic_level->MinVddcPhases = 1;
-
- if (pi->vddc_phase_shed_control)
- ci_populate_phase_value_based_on_sclk(adev,
- &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
- engine_clock,
- &graphic_level->MinVddcPhases);
-
- graphic_level->ActivityLevel = sclk_activity_level_t;
-
- graphic_level->CcPwrDynRm = 0;
- graphic_level->CcPwrDynRm1 = 0;
- graphic_level->EnabledForThrottle = 1;
- graphic_level->UpH = 0;
- graphic_level->DownH = 0;
- graphic_level->VoltageDownH = 0;
- graphic_level->PowerThrottle = 0;
-
- if (pi->caps_sclk_ds)
- graphic_level->DeepSleepDivId = ci_get_sleep_divider_id_from_clock(engine_clock,
- CISLAND_MINIMUM_ENGINE_CLOCK);
-
- graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
- graphic_level->Flags = cpu_to_be32(graphic_level->Flags);
- graphic_level->MinVddc = cpu_to_be32(graphic_level->MinVddc * VOLTAGE_SCALE);
- graphic_level->MinVddcPhases = cpu_to_be32(graphic_level->MinVddcPhases);
- graphic_level->SclkFrequency = cpu_to_be32(graphic_level->SclkFrequency);
- graphic_level->ActivityLevel = cpu_to_be16(graphic_level->ActivityLevel);
- graphic_level->CgSpllFuncCntl3 = cpu_to_be32(graphic_level->CgSpllFuncCntl3);
- graphic_level->CgSpllFuncCntl4 = cpu_to_be32(graphic_level->CgSpllFuncCntl4);
- graphic_level->SpllSpreadSpectrum = cpu_to_be32(graphic_level->SpllSpreadSpectrum);
- graphic_level->SpllSpreadSpectrum2 = cpu_to_be32(graphic_level->SpllSpreadSpectrum2);
- graphic_level->CcPwrDynRm = cpu_to_be32(graphic_level->CcPwrDynRm);
- graphic_level->CcPwrDynRm1 = cpu_to_be32(graphic_level->CcPwrDynRm1);
-
- return 0;
-}
-
-static int ci_populate_all_graphic_levels(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_dpm_table *dpm_table = &pi->dpm_table;
- u32 level_array_address = pi->dpm_table_start +
- offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
- u32 level_array_size = sizeof(SMU7_Discrete_GraphicsLevel) *
- SMU7_MAX_LEVELS_GRAPHICS;
- SMU7_Discrete_GraphicsLevel *levels = pi->smc_state_table.GraphicsLevel;
- u32 i, ret;
-
- memset(levels, 0, level_array_size);
-
- for (i = 0; i < dpm_table->sclk_table.count; i++) {
- ret = ci_populate_single_graphic_level(adev,
- dpm_table->sclk_table.dpm_levels[i].value,
- (u16)pi->activity_target[i],
- &pi->smc_state_table.GraphicsLevel[i]);
- if (ret)
- return ret;
- if (i > 1)
- pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
- if (i == (dpm_table->sclk_table.count - 1))
- pi->smc_state_table.GraphicsLevel[i].DisplayWatermark =
- PPSMC_DISPLAY_WATERMARK_HIGH;
- }
- pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
-
- pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
-
- ret = amdgpu_ci_copy_bytes_to_smc(adev, level_array_address,
- (u8 *)levels, level_array_size,
- pi->sram_end);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int ci_populate_ulv_state(struct amdgpu_device *adev,
- SMU7_Discrete_Ulv *ulv_level)
-{
- return ci_populate_ulv_level(adev, ulv_level);
-}
-
-static int ci_populate_all_memory_levels(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_dpm_table *dpm_table = &pi->dpm_table;
- u32 level_array_address = pi->dpm_table_start +
- offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
- u32 level_array_size = sizeof(SMU7_Discrete_MemoryLevel) *
- SMU7_MAX_LEVELS_MEMORY;
- SMU7_Discrete_MemoryLevel *levels = pi->smc_state_table.MemoryLevel;
- u32 i, ret;
-
- memset(levels, 0, level_array_size);
-
- for (i = 0; i < dpm_table->mclk_table.count; i++) {
- if (dpm_table->mclk_table.dpm_levels[i].value == 0)
- return -EINVAL;
- ret = ci_populate_single_memory_level(adev,
- dpm_table->mclk_table.dpm_levels[i].value,
- &pi->smc_state_table.MemoryLevel[i]);
- if (ret)
- return ret;
- }
-
- if ((dpm_table->mclk_table.count >= 2) &&
- ((adev->pdev->device == 0x67B0) || (adev->pdev->device == 0x67B1))) {
- pi->smc_state_table.MemoryLevel[1].MinVddc =
- pi->smc_state_table.MemoryLevel[0].MinVddc;
- pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
- pi->smc_state_table.MemoryLevel[0].MinVddcPhases;
- }
-
- pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F);
-
- pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count;
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
-
- pi->smc_state_table.MemoryLevel[dpm_table->mclk_table.count - 1].DisplayWatermark =
- PPSMC_DISPLAY_WATERMARK_HIGH;
-
- ret = amdgpu_ci_copy_bytes_to_smc(adev, level_array_address,
- (u8 *)levels, level_array_size,
- pi->sram_end);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void ci_reset_single_dpm_table(struct amdgpu_device *adev,
- struct ci_single_dpm_table* dpm_table,
- u32 count)
-{
- u32 i;
-
- dpm_table->count = count;
- for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
- dpm_table->dpm_levels[i].enabled = false;
-}
-
-static void ci_setup_pcie_table_entry(struct ci_single_dpm_table* dpm_table,
- u32 index, u32 pcie_gen, u32 pcie_lanes)
-{
- dpm_table->dpm_levels[index].value = pcie_gen;
- dpm_table->dpm_levels[index].param1 = pcie_lanes;
- dpm_table->dpm_levels[index].enabled = true;
-}
-
-static int ci_setup_default_pcie_tables(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (!pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels)
- return -EINVAL;
-
- if (pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) {
- pi->pcie_gen_powersaving = pi->pcie_gen_performance;
- pi->pcie_lane_powersaving = pi->pcie_lane_performance;
- } else if (!pi->use_pcie_performance_levels && pi->use_pcie_powersaving_levels) {
- pi->pcie_gen_performance = pi->pcie_gen_powersaving;
- pi->pcie_lane_performance = pi->pcie_lane_powersaving;
- }
-
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.pcie_speed_table,
- SMU7_MAX_LEVELS_LINK);
-
- if (adev->asic_type == CHIP_BONAIRE)
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
- pi->pcie_gen_powersaving.min,
- pi->pcie_lane_powersaving.max);
- else
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
- pi->pcie_gen_powersaving.min,
- pi->pcie_lane_powersaving.min);
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1,
- pi->pcie_gen_performance.min,
- pi->pcie_lane_performance.min);
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 2,
- pi->pcie_gen_powersaving.min,
- pi->pcie_lane_powersaving.max);
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 3,
- pi->pcie_gen_performance.min,
- pi->pcie_lane_performance.max);
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 4,
- pi->pcie_gen_powersaving.max,
- pi->pcie_lane_powersaving.max);
- ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 5,
- pi->pcie_gen_performance.max,
- pi->pcie_lane_performance.max);
-
- pi->dpm_table.pcie_speed_table.count = 6;
-
- return 0;
-}
-
-static int ci_setup_default_dpm_tables(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *allowed_sclk_vddc_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- struct amdgpu_clock_voltage_dependency_table *allowed_mclk_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
- struct amdgpu_cac_leakage_table *std_voltage_table =
- &adev->pm.dpm.dyn_state.cac_leakage_table;
- u32 i;
-
- if (allowed_sclk_vddc_table == NULL)
- return -EINVAL;
- if (allowed_sclk_vddc_table->count < 1)
- return -EINVAL;
- if (allowed_mclk_table == NULL)
- return -EINVAL;
- if (allowed_mclk_table->count < 1)
- return -EINVAL;
-
- memset(&pi->dpm_table, 0, sizeof(struct ci_dpm_table));
-
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.sclk_table,
- SMU7_MAX_LEVELS_GRAPHICS);
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.mclk_table,
- SMU7_MAX_LEVELS_MEMORY);
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.vddc_table,
- SMU7_MAX_LEVELS_VDDC);
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.vddci_table,
- SMU7_MAX_LEVELS_VDDCI);
- ci_reset_single_dpm_table(adev,
- &pi->dpm_table.mvdd_table,
- SMU7_MAX_LEVELS_MVDD);
-
- pi->dpm_table.sclk_table.count = 0;
- for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
- if ((i == 0) ||
- (pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count-1].value !=
- allowed_sclk_vddc_table->entries[i].clk)) {
- pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value =
- allowed_sclk_vddc_table->entries[i].clk;
- pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled =
- (i == 0) ? true : false;
- pi->dpm_table.sclk_table.count++;
- }
- }
-
- pi->dpm_table.mclk_table.count = 0;
- for (i = 0; i < allowed_mclk_table->count; i++) {
- if ((i == 0) ||
- (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value !=
- allowed_mclk_table->entries[i].clk)) {
- pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value =
- allowed_mclk_table->entries[i].clk;
- pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled =
- (i == 0) ? true : false;
- pi->dpm_table.mclk_table.count++;
- }
- }
-
- for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
- pi->dpm_table.vddc_table.dpm_levels[i].value =
- allowed_sclk_vddc_table->entries[i].v;
- pi->dpm_table.vddc_table.dpm_levels[i].param1 =
- std_voltage_table->entries[i].leakage;
- pi->dpm_table.vddc_table.dpm_levels[i].enabled = true;
- }
- pi->dpm_table.vddc_table.count = allowed_sclk_vddc_table->count;
-
- allowed_mclk_table = &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
- if (allowed_mclk_table) {
- for (i = 0; i < allowed_mclk_table->count; i++) {
- pi->dpm_table.vddci_table.dpm_levels[i].value =
- allowed_mclk_table->entries[i].v;
- pi->dpm_table.vddci_table.dpm_levels[i].enabled = true;
- }
- pi->dpm_table.vddci_table.count = allowed_mclk_table->count;
- }
-
- allowed_mclk_table = &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk;
- if (allowed_mclk_table) {
- for (i = 0; i < allowed_mclk_table->count; i++) {
- pi->dpm_table.mvdd_table.dpm_levels[i].value =
- allowed_mclk_table->entries[i].v;
- pi->dpm_table.mvdd_table.dpm_levels[i].enabled = true;
- }
- pi->dpm_table.mvdd_table.count = allowed_mclk_table->count;
- }
-
- ci_setup_default_pcie_tables(adev);
-
- /* save a copy of the default DPM table */
- memcpy(&(pi->golden_dpm_table), &(pi->dpm_table),
- sizeof(struct ci_dpm_table));
-
- return 0;
-}
-
-static int ci_find_boot_level(struct ci_single_dpm_table *table,
- u32 value, u32 *boot_level)
-{
- u32 i;
- int ret = -EINVAL;
-
- for(i = 0; i < table->count; i++) {
- if (value == table->dpm_levels[i].value) {
- *boot_level = i;
- ret = 0;
- }
- }
-
- return ret;
-}
-
-static int ci_init_smc_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ulv_parm *ulv = &pi->ulv;
- struct amdgpu_ps *amdgpu_boot_state = adev->pm.dpm.boot_ps;
- SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
- int ret;
-
- ret = ci_setup_default_dpm_tables(adev);
- if (ret)
- return ret;
-
- if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE)
- ci_populate_smc_voltage_tables(adev, table);
-
- ci_init_fps_limits(adev);
-
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
- table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
-
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
- table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
-
- if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
- table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
-
- if (ulv->supported) {
- ret = ci_populate_ulv_state(adev, &pi->smc_state_table.Ulv);
- if (ret)
- return ret;
- WREG32_SMC(ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
- }
-
- ret = ci_populate_all_graphic_levels(adev);
- if (ret)
- return ret;
-
- ret = ci_populate_all_memory_levels(adev);
- if (ret)
- return ret;
-
- ci_populate_smc_link_level(adev, table);
-
- ret = ci_populate_smc_acpi_level(adev, table);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_vce_level(adev, table);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_acp_level(adev, table);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_samu_level(adev, table);
- if (ret)
- return ret;
-
- ret = ci_do_program_memory_timing_parameters(adev);
- if (ret)
- return ret;
-
- ret = ci_populate_smc_uvd_level(adev, table);
- if (ret)
- return ret;
-
- table->UvdBootLevel = 0;
- table->VceBootLevel = 0;
- table->AcpBootLevel = 0;
- table->SamuBootLevel = 0;
- table->GraphicsBootLevel = 0;
- table->MemoryBootLevel = 0;
-
- ret = ci_find_boot_level(&pi->dpm_table.sclk_table,
- pi->vbios_boot_state.sclk_bootup_value,
- (u32 *)&pi->smc_state_table.GraphicsBootLevel);
-
- ret = ci_find_boot_level(&pi->dpm_table.mclk_table,
- pi->vbios_boot_state.mclk_bootup_value,
- (u32 *)&pi->smc_state_table.MemoryBootLevel);
-
- table->BootVddc = pi->vbios_boot_state.vddc_bootup_value;
- table->BootVddci = pi->vbios_boot_state.vddci_bootup_value;
- table->BootMVdd = pi->vbios_boot_state.mvdd_bootup_value;
-
- ci_populate_smc_initial_state(adev, amdgpu_boot_state);
-
- ret = ci_populate_bapm_parameters_in_dpm_table(adev);
- if (ret)
- return ret;
-
- table->UVDInterval = 1;
- table->VCEInterval = 1;
- table->ACPInterval = 1;
- table->SAMUInterval = 1;
- table->GraphicsVoltageChangeEnable = 1;
- table->GraphicsThermThrottleEnable = 1;
- table->GraphicsInterval = 1;
- table->VoltageInterval = 1;
- table->ThermalInterval = 1;
- table->TemperatureLimitHigh = (u16)((pi->thermal_temp_setting.temperature_high *
- CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
- table->TemperatureLimitLow = (u16)((pi->thermal_temp_setting.temperature_low *
- CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
- table->MemoryVoltageChangeEnable = 1;
- table->MemoryInterval = 1;
- table->VoltageResponseTime = 0;
- table->VddcVddciDelta = 4000;
- table->PhaseResponseTime = 0;
- table->MemoryThermThrottleEnable = 1;
- table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1;
- table->PCIeGenInterval = 1;
- if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2)
- table->SVI2Enable = 1;
- else
- table->SVI2Enable = 0;
-
- table->ThermGpio = 17;
- table->SclkStepSize = 0x4000;
-
- table->SystemFlags = cpu_to_be32(table->SystemFlags);
- table->SmioMaskVddcVid = cpu_to_be32(table->SmioMaskVddcVid);
- table->SmioMaskVddcPhase = cpu_to_be32(table->SmioMaskVddcPhase);
- table->SmioMaskVddciVid = cpu_to_be32(table->SmioMaskVddciVid);
- table->SmioMaskMvddVid = cpu_to_be32(table->SmioMaskMvddVid);
- table->SclkStepSize = cpu_to_be32(table->SclkStepSize);
- table->TemperatureLimitHigh = cpu_to_be16(table->TemperatureLimitHigh);
- table->TemperatureLimitLow = cpu_to_be16(table->TemperatureLimitLow);
- table->VddcVddciDelta = cpu_to_be16(table->VddcVddciDelta);
- table->VoltageResponseTime = cpu_to_be16(table->VoltageResponseTime);
- table->PhaseResponseTime = cpu_to_be16(table->PhaseResponseTime);
- table->BootVddc = cpu_to_be16(table->BootVddc * VOLTAGE_SCALE);
- table->BootVddci = cpu_to_be16(table->BootVddci * VOLTAGE_SCALE);
- table->BootMVdd = cpu_to_be16(table->BootMVdd * VOLTAGE_SCALE);
-
- ret = amdgpu_ci_copy_bytes_to_smc(adev,
- pi->dpm_table_start +
- offsetof(SMU7_Discrete_DpmTable, SystemFlags),
- (u8 *)&table->SystemFlags,
- sizeof(SMU7_Discrete_DpmTable) - 3 * sizeof(SMU7_PIDController),
- pi->sram_end);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void ci_trim_single_dpm_states(struct amdgpu_device *adev,
- struct ci_single_dpm_table *dpm_table,
- u32 low_limit, u32 high_limit)
-{
- u32 i;
-
- for (i = 0; i < dpm_table->count; i++) {
- if ((dpm_table->dpm_levels[i].value < low_limit) ||
- (dpm_table->dpm_levels[i].value > high_limit))
- dpm_table->dpm_levels[i].enabled = false;
- else
- dpm_table->dpm_levels[i].enabled = true;
- }
-}
-
-static void ci_trim_pcie_dpm_states(struct amdgpu_device *adev,
- u32 speed_low, u32 lanes_low,
- u32 speed_high, u32 lanes_high)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
- u32 i, j;
-
- for (i = 0; i < pcie_table->count; i++) {
- if ((pcie_table->dpm_levels[i].value < speed_low) ||
- (pcie_table->dpm_levels[i].param1 < lanes_low) ||
- (pcie_table->dpm_levels[i].value > speed_high) ||
- (pcie_table->dpm_levels[i].param1 > lanes_high))
- pcie_table->dpm_levels[i].enabled = false;
- else
- pcie_table->dpm_levels[i].enabled = true;
- }
-
- for (i = 0; i < pcie_table->count; i++) {
- if (pcie_table->dpm_levels[i].enabled) {
- for (j = i + 1; j < pcie_table->count; j++) {
- if (pcie_table->dpm_levels[j].enabled) {
- if ((pcie_table->dpm_levels[i].value == pcie_table->dpm_levels[j].value) &&
- (pcie_table->dpm_levels[i].param1 == pcie_table->dpm_levels[j].param1))
- pcie_table->dpm_levels[j].enabled = false;
- }
- }
- }
- }
-}
-
-static int ci_trim_dpm_states(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_state)
-{
- struct ci_ps *state = ci_get_ps(amdgpu_state);
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 high_limit_count;
-
- if (state->performance_level_count < 1)
- return -EINVAL;
-
- if (state->performance_level_count == 1)
- high_limit_count = 0;
- else
- high_limit_count = 1;
-
- ci_trim_single_dpm_states(adev,
- &pi->dpm_table.sclk_table,
- state->performance_levels[0].sclk,
- state->performance_levels[high_limit_count].sclk);
-
- ci_trim_single_dpm_states(adev,
- &pi->dpm_table.mclk_table,
- state->performance_levels[0].mclk,
- state->performance_levels[high_limit_count].mclk);
-
- ci_trim_pcie_dpm_states(adev,
- state->performance_levels[0].pcie_gen,
- state->performance_levels[0].pcie_lane,
- state->performance_levels[high_limit_count].pcie_gen,
- state->performance_levels[high_limit_count].pcie_lane);
-
- return 0;
-}
-
-static int ci_apply_disp_minimum_voltage_request(struct amdgpu_device *adev)
-{
- struct amdgpu_clock_voltage_dependency_table *disp_voltage_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk;
- struct amdgpu_clock_voltage_dependency_table *vddc_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- u32 requested_voltage = 0;
- u32 i;
-
- if (disp_voltage_table == NULL)
- return -EINVAL;
- if (!disp_voltage_table->count)
- return -EINVAL;
-
- for (i = 0; i < disp_voltage_table->count; i++) {
- if (adev->clock.current_dispclk == disp_voltage_table->entries[i].clk)
- requested_voltage = disp_voltage_table->entries[i].v;
- }
-
- for (i = 0; i < vddc_table->count; i++) {
- if (requested_voltage <= vddc_table->entries[i].v) {
- requested_voltage = vddc_table->entries[i].v;
- return (amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_VddC_Request,
- requested_voltage * VOLTAGE_SCALE) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
- }
- }
-
- return -EINVAL;
-}
-
-static int ci_upload_dpm_level_enable_mask(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- PPSMC_Result result;
-
- ci_apply_disp_minimum_voltage_request(adev);
-
- if (!pi->sclk_dpm_key_disabled) {
- if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
- result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
- if (result != PPSMC_Result_OK)
- return -EINVAL;
- }
- }
-
- if (!pi->mclk_dpm_key_disabled) {
- if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
- result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_MCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
- if (result != PPSMC_Result_OK)
- return -EINVAL;
- }
- }
-
-#if 0
- if (!pi->pcie_dpm_key_disabled) {
- if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
- result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_PCIeDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
- if (result != PPSMC_Result_OK)
- return -EINVAL;
- }
- }
-#endif
-
- return 0;
-}
-
-static void ci_find_dpm_states_clocks_in_dpm_table(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *state = ci_get_ps(amdgpu_state);
- struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
- u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
- struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
- u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
- u32 i;
-
- pi->need_update_smu7_dpm_table = 0;
-
- for (i = 0; i < sclk_table->count; i++) {
- if (sclk == sclk_table->dpm_levels[i].value)
- break;
- }
-
- if (i >= sclk_table->count) {
- pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
- } else {
- /* XXX check display min clock requirements */
- if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK)
- pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
- }
-
- for (i = 0; i < mclk_table->count; i++) {
- if (mclk == mclk_table->dpm_levels[i].value)
- break;
- }
-
- if (i >= mclk_table->count)
- pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
-
- if (adev->pm.dpm.current_active_crtc_count !=
- adev->pm.dpm.new_active_crtc_count)
- pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
-}
-
-static int ci_populate_and_upload_sclk_mclk_dpm_levels(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *state = ci_get_ps(amdgpu_state);
- u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
- u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
- struct ci_dpm_table *dpm_table = &pi->dpm_table;
- int ret;
-
- if (!pi->need_update_smu7_dpm_table)
- return 0;
-
- if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
- dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value = sclk;
-
- if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
- dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value = mclk;
-
- if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) {
- ret = ci_populate_all_graphic_levels(adev);
- if (ret)
- return ret;
- }
-
- if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
- ret = ci_populate_all_memory_levels(adev);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct amdgpu_clock_and_voltage_limits *max_limits;
- int i;
-
- if (adev->pm.ac_power)
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- else
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
-
- if (enable) {
- pi->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
-
- for (i = adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
- if (adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
- pi->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
-
- if (!pi->caps_uvd_dpm)
- break;
- }
- }
-
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_UVDDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.uvd_dpm_enable_mask);
-
- if (pi->last_mclk_dpm_enable_mask & 0x1) {
- pi->uvd_enabled = true;
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_MCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
- }
- } else {
- if (pi->uvd_enabled) {
- pi->uvd_enabled = false;
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1;
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_MCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
- }
- }
-
- return (amdgpu_ci_send_msg_to_smc(adev, enable ?
- PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
-}
-
-static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct amdgpu_clock_and_voltage_limits *max_limits;
- int i;
-
- if (adev->pm.ac_power)
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- else
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
-
- if (enable) {
- pi->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
- for (i = adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
- if (adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
- pi->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
-
- if (!pi->caps_vce_dpm)
- break;
- }
- }
-
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_VCEDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.vce_dpm_enable_mask);
- }
-
- return (amdgpu_ci_send_msg_to_smc(adev, enable ?
- PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
-}
-
-#if 0
-static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct amdgpu_clock_and_voltage_limits *max_limits;
- int i;
-
- if (adev->pm.ac_power)
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- else
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
-
- if (enable) {
- pi->dpm_level_enable_mask.samu_dpm_enable_mask = 0;
- for (i = adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
- if (adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
- pi->dpm_level_enable_mask.samu_dpm_enable_mask |= 1 << i;
-
- if (!pi->caps_samu_dpm)
- break;
- }
- }
-
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SAMUDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.samu_dpm_enable_mask);
- }
- return (amdgpu_ci_send_msg_to_smc(adev, enable ?
- PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
-}
-
-static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- const struct amdgpu_clock_and_voltage_limits *max_limits;
- int i;
-
- if (adev->pm.ac_power)
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- else
- max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
-
- if (enable) {
- pi->dpm_level_enable_mask.acp_dpm_enable_mask = 0;
- for (i = adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
- if (adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
- pi->dpm_level_enable_mask.acp_dpm_enable_mask |= 1 << i;
-
- if (!pi->caps_acp_dpm)
- break;
- }
- }
-
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ACPDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.acp_dpm_enable_mask);
- }
-
- return (amdgpu_ci_send_msg_to_smc(adev, enable ?
- PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
-}
-#endif
-
-static int ci_update_uvd_dpm(struct amdgpu_device *adev, bool gate)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
- int ret = 0;
-
- if (!gate) {
- /* turn the clocks on when decoding */
- if (pi->caps_uvd_dpm ||
- (adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count <= 0))
- pi->smc_state_table.UvdBootLevel = 0;
- else
- pi->smc_state_table.UvdBootLevel =
- adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1;
-
- tmp = RREG32_SMC(ixDPM_TABLE_475);
- tmp &= ~DPM_TABLE_475__UvdBootLevel_MASK;
- tmp |= (pi->smc_state_table.UvdBootLevel << DPM_TABLE_475__UvdBootLevel__SHIFT);
- WREG32_SMC(ixDPM_TABLE_475, tmp);
- ret = ci_enable_uvd_dpm(adev, true);
- } else {
- ret = ci_enable_uvd_dpm(adev, false);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static u8 ci_get_vce_boot_level(struct amdgpu_device *adev)
-{
- u8 i;
- u32 min_evclk = 30000; /* ??? */
- struct amdgpu_vce_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
-
- for (i = 0; i < table->count; i++) {
- if (table->entries[i].evclk >= min_evclk)
- return i;
- }
-
- return table->count - 1;
-}
-
-static int ci_update_vce_dpm(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_new_state,
- struct amdgpu_ps *amdgpu_current_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret = 0;
- u32 tmp;
-
- if (amdgpu_current_state->evclk != amdgpu_new_state->evclk) {
- if (amdgpu_new_state->evclk) {
- pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(adev);
- tmp = RREG32_SMC(ixDPM_TABLE_475);
- tmp &= ~DPM_TABLE_475__VceBootLevel_MASK;
- tmp |= (pi->smc_state_table.VceBootLevel << DPM_TABLE_475__VceBootLevel__SHIFT);
- WREG32_SMC(ixDPM_TABLE_475, tmp);
-
- ret = ci_enable_vce_dpm(adev, true);
- } else {
- ret = ci_enable_vce_dpm(adev, false);
- if (ret)
- return ret;
- }
- }
- return ret;
-}
-
-#if 0
-static int ci_update_samu_dpm(struct amdgpu_device *adev, bool gate)
-{
- return ci_enable_samu_dpm(adev, gate);
-}
-
-static int ci_update_acp_dpm(struct amdgpu_device *adev, bool gate)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp;
-
- if (!gate) {
- pi->smc_state_table.AcpBootLevel = 0;
-
- tmp = RREG32_SMC(ixDPM_TABLE_475);
- tmp &= ~AcpBootLevel_MASK;
- tmp |= AcpBootLevel(pi->smc_state_table.AcpBootLevel);
- WREG32_SMC(ixDPM_TABLE_475, tmp);
- }
-
- return ci_enable_acp_dpm(adev, !gate);
-}
-#endif
-
-static int ci_generate_dpm_level_enable_mask(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
-
- ret = ci_trim_dpm_states(adev, amdgpu_state);
- if (ret)
- return ret;
-
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&pi->dpm_table.sclk_table);
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&pi->dpm_table.mclk_table);
- pi->last_mclk_dpm_enable_mask =
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
- if (pi->uvd_enabled) {
- if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
- }
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
- ci_get_dpm_level_enable_mask_value(&pi->dpm_table.pcie_speed_table);
-
- return 0;
-}
-
-static u32 ci_get_lowest_enabled_level(struct amdgpu_device *adev,
- u32 level_mask)
-{
- u32 level = 0;
-
- while ((level_mask & (1 << level)) == 0)
- level++;
-
- return level;
-}
-
-
-static int ci_dpm_force_performance_level(void *handle,
- enum amd_dpm_forced_level level)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 tmp, levels, i;
- int ret;
-
- if (level == AMD_DPM_FORCED_LEVEL_HIGH) {
- if ((!pi->pcie_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
- levels = 0;
- tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
- while (tmp >>= 1)
- levels++;
- if (levels) {
- ret = ci_dpm_force_state_pcie(adev, level);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_1) &
- TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- }
- if ((!pi->sclk_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
- levels = 0;
- tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
- while (tmp >>= 1)
- levels++;
- if (levels) {
- ret = ci_dpm_force_state_sclk(adev, levels);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- }
- if ((!pi->mclk_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
- levels = 0;
- tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
- while (tmp >>= 1)
- levels++;
- if (levels) {
- ret = ci_dpm_force_state_mclk(adev, levels);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- }
- } else if (level == AMD_DPM_FORCED_LEVEL_LOW) {
- if ((!pi->sclk_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
- levels = ci_get_lowest_enabled_level(adev,
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
- ret = ci_dpm_force_state_sclk(adev, levels);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- if ((!pi->mclk_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
- levels = ci_get_lowest_enabled_level(adev,
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
- ret = ci_dpm_force_state_mclk(adev, levels);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- if ((!pi->pcie_dpm_key_disabled) &&
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
- levels = ci_get_lowest_enabled_level(adev,
- pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
- ret = ci_dpm_force_state_pcie(adev, levels);
- if (ret)
- return ret;
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_1) &
- TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX_MASK) >>
- TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX__SHIFT;
- if (tmp == levels)
- break;
- udelay(1);
- }
- }
- } else if (level == AMD_DPM_FORCED_LEVEL_AUTO) {
- if (!pi->pcie_dpm_key_disabled) {
- PPSMC_Result smc_result;
-
- smc_result = amdgpu_ci_send_msg_to_smc(adev,
- PPSMC_MSG_PCIeDPM_UnForceLevel);
- if (smc_result != PPSMC_Result_OK)
- return -EINVAL;
- }
- ret = ci_upload_dpm_level_enable_mask(adev);
- if (ret)
- return ret;
- }
-
- adev->pm.dpm.forced_level = level;
-
- return 0;
-}
-
-static int ci_set_mc_special_registers(struct amdgpu_device *adev,
- struct ci_mc_reg_table *table)
-{
- u8 i, j, k;
- u32 temp_reg;
-
- for (i = 0, j = table->last; i < table->last; i++) {
- if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- switch(table->mc_reg_address[i].s1) {
- case mmMC_SEQ_MISC1:
- temp_reg = RREG32(mmMC_PMG_CMD_EMRS);
- table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
- table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
- for (k = 0; k < table->num_entries; k++) {
- table->mc_reg_table_entry[k].mc_data[j] =
- ((temp_reg & 0xffff0000)) | ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
- }
- j++;
-
- if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- temp_reg = RREG32(mmMC_PMG_CMD_MRS);
- table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
- table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
- for (k = 0; k < table->num_entries; k++) {
- table->mc_reg_table_entry[k].mc_data[j] =
- (temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
- if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5)
- table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
- }
- j++;
-
- if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) {
- if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
- table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
- for (k = 0; k < table->num_entries; k++) {
- table->mc_reg_table_entry[k].mc_data[j] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
- }
- j++;
- }
- break;
- case mmMC_SEQ_RESERVE_M:
- temp_reg = RREG32(mmMC_PMG_CMD_MRS1);
- table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
- table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
- for (k = 0; k < table->num_entries; k++) {
- table->mc_reg_table_entry[k].mc_data[j] =
- (temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
- }
- j++;
- break;
- default:
- break;
- }
-
- }
-
- table->last = j;
-
- return 0;
-}
-
-static bool ci_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
-{
- bool result = true;
-
- switch(in_reg) {
- case mmMC_SEQ_RAS_TIMING:
- *out_reg = mmMC_SEQ_RAS_TIMING_LP;
- break;
- case mmMC_SEQ_DLL_STBY:
- *out_reg = mmMC_SEQ_DLL_STBY_LP;
- break;
- case mmMC_SEQ_G5PDX_CMD0:
- *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
- break;
- case mmMC_SEQ_G5PDX_CMD1:
- *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
- break;
- case mmMC_SEQ_G5PDX_CTRL:
- *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
- break;
- case mmMC_SEQ_CAS_TIMING:
- *out_reg = mmMC_SEQ_CAS_TIMING_LP;
- break;
- case mmMC_SEQ_MISC_TIMING:
- *out_reg = mmMC_SEQ_MISC_TIMING_LP;
- break;
- case mmMC_SEQ_MISC_TIMING2:
- *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
- break;
- case mmMC_SEQ_PMG_DVS_CMD:
- *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
- break;
- case mmMC_SEQ_PMG_DVS_CTL:
- *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
- break;
- case mmMC_SEQ_RD_CTL_D0:
- *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
- break;
- case mmMC_SEQ_RD_CTL_D1:
- *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
- break;
- case mmMC_SEQ_WR_CTL_D0:
- *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
- break;
- case mmMC_SEQ_WR_CTL_D1:
- *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
- break;
- case mmMC_PMG_CMD_EMRS:
- *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
- break;
- case mmMC_PMG_CMD_MRS:
- *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
- break;
- case mmMC_PMG_CMD_MRS1:
- *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
- break;
- case mmMC_SEQ_PMG_TIMING:
- *out_reg = mmMC_SEQ_PMG_TIMING_LP;
- break;
- case mmMC_PMG_CMD_MRS2:
- *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
- break;
- case mmMC_SEQ_WR_CTL_2:
- *out_reg = mmMC_SEQ_WR_CTL_2_LP;
- break;
- default:
- result = false;
- break;
- }
-
- return result;
-}
-
-static void ci_set_valid_flag(struct ci_mc_reg_table *table)
-{
- u8 i, j;
-
- for (i = 0; i < table->last; i++) {
- for (j = 1; j < table->num_entries; j++) {
- if (table->mc_reg_table_entry[j-1].mc_data[i] !=
- table->mc_reg_table_entry[j].mc_data[i]) {
- table->valid_flag |= 1 << i;
- break;
- }
- }
- }
-}
-
-static void ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
-{
- u32 i;
- u16 address;
-
- for (i = 0; i < table->last; i++) {
- table->mc_reg_address[i].s0 =
- ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
- address : table->mc_reg_address[i].s1;
- }
-}
-
-static int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table,
- struct ci_mc_reg_table *ci_table)
-{
- u8 i, j;
-
- if (table->last > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- if (table->num_entries > MAX_AC_TIMING_ENTRIES)
- return -EINVAL;
-
- for (i = 0; i < table->last; i++)
- ci_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
-
- ci_table->last = table->last;
-
- for (i = 0; i < table->num_entries; i++) {
- ci_table->mc_reg_table_entry[i].mclk_max =
- table->mc_reg_table_entry[i].mclk_max;
- for (j = 0; j < table->last; j++)
- ci_table->mc_reg_table_entry[i].mc_data[j] =
- table->mc_reg_table_entry[i].mc_data[j];
- }
- ci_table->num_entries = table->num_entries;
-
- return 0;
-}
-
-static int ci_register_patching_mc_seq(struct amdgpu_device *adev,
- struct ci_mc_reg_table *table)
-{
- u8 i, k;
- u32 tmp;
- bool patch;
-
- tmp = RREG32(mmMC_SEQ_MISC0);
- patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
-
- if (patch &&
- ((adev->pdev->device == 0x67B0) ||
- (adev->pdev->device == 0x67B1))) {
- for (i = 0; i < table->last; i++) {
- if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- switch (table->mc_reg_address[i].s1) {
- case mmMC_SEQ_MISC1:
- for (k = 0; k < table->num_entries; k++) {
- if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
- (table->mc_reg_table_entry[k].mclk_max == 137500))
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) |
- 0x00000007;
- }
- break;
- case mmMC_SEQ_WR_CTL_D0:
- for (k = 0; k < table->num_entries; k++) {
- if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
- (table->mc_reg_table_entry[k].mclk_max == 137500))
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
- 0x0000D0DD;
- }
- break;
- case mmMC_SEQ_WR_CTL_D1:
- for (k = 0; k < table->num_entries; k++) {
- if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
- (table->mc_reg_table_entry[k].mclk_max == 137500))
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
- 0x0000D0DD;
- }
- break;
- case mmMC_SEQ_WR_CTL_2:
- for (k = 0; k < table->num_entries; k++) {
- if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
- (table->mc_reg_table_entry[k].mclk_max == 137500))
- table->mc_reg_table_entry[k].mc_data[i] = 0;
- }
- break;
- case mmMC_SEQ_CAS_TIMING:
- for (k = 0; k < table->num_entries; k++) {
- if (table->mc_reg_table_entry[k].mclk_max == 125000)
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
- 0x000C0140;
- else if (table->mc_reg_table_entry[k].mclk_max == 137500)
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
- 0x000C0150;
- }
- break;
- case mmMC_SEQ_MISC_TIMING:
- for (k = 0; k < table->num_entries; k++) {
- if (table->mc_reg_table_entry[k].mclk_max == 125000)
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
- 0x00000030;
- else if (table->mc_reg_table_entry[k].mclk_max == 137500)
- table->mc_reg_table_entry[k].mc_data[i] =
- (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
- 0x00000035;
- }
- break;
- default:
- break;
- }
- }
-
- WREG32(mmMC_SEQ_IO_DEBUG_INDEX, 3);
- tmp = RREG32(mmMC_SEQ_IO_DEBUG_DATA);
- tmp = (tmp & 0xFFF8FFFF) | (1 << 16);
- WREG32(mmMC_SEQ_IO_DEBUG_INDEX, 3);
- WREG32(mmMC_SEQ_IO_DEBUG_DATA, tmp);
- }
-
- return 0;
-}
-
-static int ci_initialize_mc_reg_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct atom_mc_reg_table *table;
- struct ci_mc_reg_table *ci_table = &pi->mc_reg_table;
- u8 module_index = ci_get_memory_module_index(adev);
- int ret;
-
- table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
-
- WREG32(mmMC_SEQ_RAS_TIMING_LP, RREG32(mmMC_SEQ_RAS_TIMING));
- WREG32(mmMC_SEQ_CAS_TIMING_LP, RREG32(mmMC_SEQ_CAS_TIMING));
- WREG32(mmMC_SEQ_DLL_STBY_LP, RREG32(mmMC_SEQ_DLL_STBY));
- WREG32(mmMC_SEQ_G5PDX_CMD0_LP, RREG32(mmMC_SEQ_G5PDX_CMD0));
- WREG32(mmMC_SEQ_G5PDX_CMD1_LP, RREG32(mmMC_SEQ_G5PDX_CMD1));
- WREG32(mmMC_SEQ_G5PDX_CTRL_LP, RREG32(mmMC_SEQ_G5PDX_CTRL));
- WREG32(mmMC_SEQ_PMG_DVS_CMD_LP, RREG32(mmMC_SEQ_PMG_DVS_CMD));
- WREG32(mmMC_SEQ_PMG_DVS_CTL_LP, RREG32(mmMC_SEQ_PMG_DVS_CTL));
- WREG32(mmMC_SEQ_MISC_TIMING_LP, RREG32(mmMC_SEQ_MISC_TIMING));
- WREG32(mmMC_SEQ_MISC_TIMING2_LP, RREG32(mmMC_SEQ_MISC_TIMING2));
- WREG32(mmMC_SEQ_PMG_CMD_EMRS_LP, RREG32(mmMC_PMG_CMD_EMRS));
- WREG32(mmMC_SEQ_PMG_CMD_MRS_LP, RREG32(mmMC_PMG_CMD_MRS));
- WREG32(mmMC_SEQ_PMG_CMD_MRS1_LP, RREG32(mmMC_PMG_CMD_MRS1));
- WREG32(mmMC_SEQ_WR_CTL_D0_LP, RREG32(mmMC_SEQ_WR_CTL_D0));
- WREG32(mmMC_SEQ_WR_CTL_D1_LP, RREG32(mmMC_SEQ_WR_CTL_D1));
- WREG32(mmMC_SEQ_RD_CTL_D0_LP, RREG32(mmMC_SEQ_RD_CTL_D0));
- WREG32(mmMC_SEQ_RD_CTL_D1_LP, RREG32(mmMC_SEQ_RD_CTL_D1));
- WREG32(mmMC_SEQ_PMG_TIMING_LP, RREG32(mmMC_SEQ_PMG_TIMING));
- WREG32(mmMC_SEQ_PMG_CMD_MRS2_LP, RREG32(mmMC_PMG_CMD_MRS2));
- WREG32(mmMC_SEQ_WR_CTL_2_LP, RREG32(mmMC_SEQ_WR_CTL_2));
-
- ret = amdgpu_atombios_init_mc_reg_table(adev, module_index, table);
- if (ret)
- goto init_mc_done;
-
- ret = ci_copy_vbios_mc_reg_table(table, ci_table);
- if (ret)
- goto init_mc_done;
-
- ci_set_s0_mc_reg_index(ci_table);
-
- ret = ci_register_patching_mc_seq(adev, ci_table);
- if (ret)
- goto init_mc_done;
-
- ret = ci_set_mc_special_registers(adev, ci_table);
- if (ret)
- goto init_mc_done;
-
- ci_set_valid_flag(ci_table);
-
-init_mc_done:
- kfree(table);
-
- return ret;
-}
-
-static int ci_populate_mc_reg_addresses(struct amdgpu_device *adev,
- SMU7_Discrete_MCRegisters *mc_reg_table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 i, j;
-
- for (i = 0, j = 0; j < pi->mc_reg_table.last; j++) {
- if (pi->mc_reg_table.valid_flag & (1 << j)) {
- if (i >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
- return -EINVAL;
- mc_reg_table->address[i].s0 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s0);
- mc_reg_table->address[i].s1 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s1);
- i++;
- }
- }
-
- mc_reg_table->last = (u8)i;
-
- return 0;
-}
-
-static void ci_convert_mc_registers(const struct ci_mc_reg_entry *entry,
- SMU7_Discrete_MCRegisterSet *data,
- u32 num_entries, u32 valid_flag)
-{
- u32 i, j;
-
- for (i = 0, j = 0; j < num_entries; j++) {
- if (valid_flag & (1 << j)) {
- data->value[i] = cpu_to_be32(entry->mc_data[j]);
- i++;
- }
- }
-}
-
-static void ci_convert_mc_reg_table_entry_to_smc(struct amdgpu_device *adev,
- const u32 memory_clock,
- SMU7_Discrete_MCRegisterSet *mc_reg_table_data)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 i = 0;
-
- for(i = 0; i < pi->mc_reg_table.num_entries; i++) {
- if (memory_clock <= pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
- break;
- }
-
- if ((i == pi->mc_reg_table.num_entries) && (i > 0))
- --i;
-
- ci_convert_mc_registers(&pi->mc_reg_table.mc_reg_table_entry[i],
- mc_reg_table_data, pi->mc_reg_table.last,
- pi->mc_reg_table.valid_flag);
-}
-
-static void ci_convert_mc_reg_table_to_smc(struct amdgpu_device *adev,
- SMU7_Discrete_MCRegisters *mc_reg_table)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- u32 i;
-
- for (i = 0; i < pi->dpm_table.mclk_table.count; i++)
- ci_convert_mc_reg_table_entry_to_smc(adev,
- pi->dpm_table.mclk_table.dpm_levels[i].value,
- &mc_reg_table->data[i]);
-}
-
-static int ci_populate_initial_mc_reg_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- int ret;
-
- memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
-
- ret = ci_populate_mc_reg_addresses(adev, &pi->smc_mc_reg_table);
- if (ret)
- return ret;
- ci_convert_mc_reg_table_to_smc(adev, &pi->smc_mc_reg_table);
-
- return amdgpu_ci_copy_bytes_to_smc(adev,
- pi->mc_reg_table_start,
- (u8 *)&pi->smc_mc_reg_table,
- sizeof(SMU7_Discrete_MCRegisters),
- pi->sram_end);
-}
-
-static int ci_update_and_upload_mc_reg_table(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (!(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
- return 0;
-
- memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
-
- ci_convert_mc_reg_table_to_smc(adev, &pi->smc_mc_reg_table);
-
- return amdgpu_ci_copy_bytes_to_smc(adev,
- pi->mc_reg_table_start +
- offsetof(SMU7_Discrete_MCRegisters, data[0]),
- (u8 *)&pi->smc_mc_reg_table.data[0],
- sizeof(SMU7_Discrete_MCRegisterSet) *
- pi->dpm_table.mclk_table.count,
- pi->sram_end);
-}
-
-static void ci_enable_voltage_control(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
-
- tmp |= GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK;
- WREG32_SMC(ixGENERAL_PWRMGT, tmp);
-}
-
-static enum amdgpu_pcie_gen ci_get_maximum_link_speed(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_state)
-{
- struct ci_ps *state = ci_get_ps(amdgpu_state);
- int i;
- u16 pcie_speed, max_speed = 0;
-
- for (i = 0; i < state->performance_level_count; i++) {
- pcie_speed = state->performance_levels[i].pcie_gen;
- if (max_speed < pcie_speed)
- max_speed = pcie_speed;
- }
-
- return max_speed;
-}
-
-static u16 ci_get_current_pcie_speed(struct amdgpu_device *adev)
-{
- u32 speed_cntl = 0;
-
- speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL) &
- PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK;
- speed_cntl >>= PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
-
- return (u16)speed_cntl;
-}
-
-static int ci_get_current_pcie_lane_number(struct amdgpu_device *adev)
-{
- u32 link_width = 0;
-
- link_width = RREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL) &
- PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK;
- link_width >>= PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
-
- switch (link_width) {
- case 1:
- return 1;
- case 2:
- return 2;
- case 3:
- return 4;
- case 4:
- return 8;
- case 0:
- case 6:
- default:
- return 16;
- }
-}
-
-static void ci_request_link_speed_change_before_state_change(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_new_state,
- struct amdgpu_ps *amdgpu_current_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- enum amdgpu_pcie_gen target_link_speed =
- ci_get_maximum_link_speed(adev, amdgpu_new_state);
- enum amdgpu_pcie_gen current_link_speed;
-
- if (pi->force_pcie_gen == AMDGPU_PCIE_GEN_INVALID)
- current_link_speed = ci_get_maximum_link_speed(adev, amdgpu_current_state);
- else
- current_link_speed = pi->force_pcie_gen;
-
- pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
- pi->pspp_notify_required = false;
- if (target_link_speed > current_link_speed) {
- switch (target_link_speed) {
-#ifdef CONFIG_ACPI
- case AMDGPU_PCIE_GEN3:
- if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
- break;
- pi->force_pcie_gen = AMDGPU_PCIE_GEN2;
- if (current_link_speed == AMDGPU_PCIE_GEN2)
- break;
- case AMDGPU_PCIE_GEN2:
- if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
- break;
-#endif
- default:
- pi->force_pcie_gen = ci_get_current_pcie_speed(adev);
- break;
- }
- } else {
- if (target_link_speed < current_link_speed)
- pi->pspp_notify_required = true;
- }
-}
-
-static void ci_notify_link_speed_change_after_state_change(struct amdgpu_device *adev,
- struct amdgpu_ps *amdgpu_new_state,
- struct amdgpu_ps *amdgpu_current_state)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- enum amdgpu_pcie_gen target_link_speed =
- ci_get_maximum_link_speed(adev, amdgpu_new_state);
- u8 request;
-
- if (pi->pspp_notify_required) {
- if (target_link_speed == AMDGPU_PCIE_GEN3)
- request = PCIE_PERF_REQ_PECI_GEN3;
- else if (target_link_speed == AMDGPU_PCIE_GEN2)
- request = PCIE_PERF_REQ_PECI_GEN2;
- else
- request = PCIE_PERF_REQ_PECI_GEN1;
-
- if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
- (ci_get_current_pcie_speed(adev) > 0))
- return;
-
-#ifdef CONFIG_ACPI
- amdgpu_acpi_pcie_performance_request(adev, request, false);
-#endif
- }
-}
-
-static int ci_set_private_data_variables_based_on_pptable(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *allowed_sclk_vddc_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- struct amdgpu_clock_voltage_dependency_table *allowed_mclk_vddc_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
- struct amdgpu_clock_voltage_dependency_table *allowed_mclk_vddci_table =
- &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
-
- if (allowed_sclk_vddc_table == NULL)
- return -EINVAL;
- if (allowed_sclk_vddc_table->count < 1)
- return -EINVAL;
- if (allowed_mclk_vddc_table == NULL)
- return -EINVAL;
- if (allowed_mclk_vddc_table->count < 1)
- return -EINVAL;
- if (allowed_mclk_vddci_table == NULL)
- return -EINVAL;
- if (allowed_mclk_vddci_table->count < 1)
- return -EINVAL;
-
- pi->min_vddc_in_pp_table = allowed_sclk_vddc_table->entries[0].v;
- pi->max_vddc_in_pp_table =
- allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
-
- pi->min_vddci_in_pp_table = allowed_mclk_vddci_table->entries[0].v;
- pi->max_vddci_in_pp_table =
- allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
-
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk =
- allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk =
- allowed_mclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc =
- allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci =
- allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
-
- return 0;
-}
-
-static void ci_patch_with_vddc_leakage(struct amdgpu_device *adev, u16 *vddc)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_leakage_voltage *leakage_table = &pi->vddc_leakage;
- u32 leakage_index;
-
- for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
- if (leakage_table->leakage_id[leakage_index] == *vddc) {
- *vddc = leakage_table->actual_voltage[leakage_index];
- break;
- }
- }
-}
-
-static void ci_patch_with_vddci_leakage(struct amdgpu_device *adev, u16 *vddci)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_leakage_voltage *leakage_table = &pi->vddci_leakage;
- u32 leakage_index;
-
- for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
- if (leakage_table->leakage_id[leakage_index] == *vddci) {
- *vddci = leakage_table->actual_voltage[leakage_index];
- break;
- }
- }
-}
-
-static void ci_patch_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_clock_voltage_dependency_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
- }
-}
-
-static void ci_patch_clock_voltage_dependency_table_with_vddci_leakage(struct amdgpu_device *adev,
- struct amdgpu_clock_voltage_dependency_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddci_leakage(adev, &table->entries[i].v);
- }
-}
-
-static void ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_vce_clock_voltage_dependency_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
- }
-}
-
-static void ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_uvd_clock_voltage_dependency_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
- }
-}
-
-static void ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_phase_shedding_limits_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddc_leakage(adev, &table->entries[i].voltage);
- }
-}
-
-static void ci_patch_clock_voltage_limits_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_clock_and_voltage_limits *table)
-{
- if (table) {
- ci_patch_with_vddc_leakage(adev, (u16 *)&table->vddc);
- ci_patch_with_vddci_leakage(adev, (u16 *)&table->vddci);
- }
-}
-
-static void ci_patch_cac_leakage_table_with_vddc_leakage(struct amdgpu_device *adev,
- struct amdgpu_cac_leakage_table *table)
-{
- u32 i;
-
- if (table) {
- for (i = 0; i < table->count; i++)
- ci_patch_with_vddc_leakage(adev, &table->entries[i].vddc);
- }
-}
-
-static void ci_patch_dependency_tables_with_leakage(struct amdgpu_device *adev)
-{
-
- ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
- ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
- ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk);
- ci_patch_clock_voltage_dependency_table_with_vddci_leakage(adev,
- &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
- ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table);
- ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table);
- ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table);
- ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table);
- ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.phase_shedding_limits_table);
- ci_patch_clock_voltage_limits_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
- ci_patch_clock_voltage_limits_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc);
- ci_patch_cac_leakage_table_with_vddc_leakage(adev,
- &adev->pm.dpm.dyn_state.cac_leakage_table);
-
-}
-
-static void ci_update_current_ps(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- struct ci_ps *new_ps = ci_get_ps(rps);
- struct ci_power_info *pi = ci_get_pi(adev);
-
- pi->current_rps = *rps;
- pi->current_ps = *new_ps;
- pi->current_rps.ps_priv = &pi->current_ps;
- adev->pm.dpm.current_ps = &pi->current_rps;
-}
-
-static void ci_update_requested_ps(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- struct ci_ps *new_ps = ci_get_ps(rps);
- struct ci_power_info *pi = ci_get_pi(adev);
-
- pi->requested_rps = *rps;
- pi->requested_ps = *new_ps;
- pi->requested_rps.ps_priv = &pi->requested_ps;
- adev->pm.dpm.requested_ps = &pi->requested_rps;
-}
-
-static int ci_dpm_pre_set_power_state(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps requested_ps = *adev->pm.dpm.requested_ps;
- struct amdgpu_ps *new_ps = &requested_ps;
-
- ci_update_requested_ps(adev, new_ps);
-
- ci_apply_state_adjust_rules(adev, &pi->requested_rps);
-
- return 0;
-}
-
-static void ci_dpm_post_set_power_state(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps *new_ps = &pi->requested_rps;
-
- ci_update_current_ps(adev, new_ps);
-}
-
-
-static void ci_dpm_setup_asic(struct amdgpu_device *adev)
-{
- ci_read_clock_registers(adev);
- ci_enable_acpi_power_management(adev);
- ci_init_sclk_t(adev);
-}
-
-static int ci_dpm_enable(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
- int ret;
-
- if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
- ci_enable_voltage_control(adev);
- ret = ci_construct_voltage_tables(adev);
- if (ret) {
- DRM_ERROR("ci_construct_voltage_tables failed\n");
- return ret;
- }
- }
- if (pi->caps_dynamic_ac_timing) {
- ret = ci_initialize_mc_reg_table(adev);
- if (ret)
- pi->caps_dynamic_ac_timing = false;
- }
- if (pi->dynamic_ss)
- ci_enable_spread_spectrum(adev, true);
- if (pi->thermal_protection)
- ci_enable_thermal_protection(adev, true);
- ci_program_sstp(adev);
- ci_enable_display_gap(adev);
- ci_program_vc(adev);
- ret = ci_upload_firmware(adev);
- if (ret) {
- DRM_ERROR("ci_upload_firmware failed\n");
- return ret;
- }
- ret = ci_process_firmware_header(adev);
- if (ret) {
- DRM_ERROR("ci_process_firmware_header failed\n");
- return ret;
- }
- ret = ci_initial_switch_from_arb_f0_to_f1(adev);
- if (ret) {
- DRM_ERROR("ci_initial_switch_from_arb_f0_to_f1 failed\n");
- return ret;
- }
- ret = ci_init_smc_table(adev);
- if (ret) {
- DRM_ERROR("ci_init_smc_table failed\n");
- return ret;
- }
- ret = ci_init_arb_table_index(adev);
- if (ret) {
- DRM_ERROR("ci_init_arb_table_index failed\n");
- return ret;
- }
- if (pi->caps_dynamic_ac_timing) {
- ret = ci_populate_initial_mc_reg_table(adev);
- if (ret) {
- DRM_ERROR("ci_populate_initial_mc_reg_table failed\n");
- return ret;
- }
- }
- ret = ci_populate_pm_base(adev);
- if (ret) {
- DRM_ERROR("ci_populate_pm_base failed\n");
- return ret;
- }
- ci_dpm_start_smc(adev);
- ci_enable_vr_hot_gpio_interrupt(adev);
- ret = ci_notify_smc_display_change(adev, false);
- if (ret) {
- DRM_ERROR("ci_notify_smc_display_change failed\n");
- return ret;
- }
- ci_enable_sclk_control(adev, true);
- ret = ci_enable_ulv(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_ulv failed\n");
- return ret;
- }
- ret = ci_enable_ds_master_switch(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_ds_master_switch failed\n");
- return ret;
- }
- ret = ci_start_dpm(adev);
- if (ret) {
- DRM_ERROR("ci_start_dpm failed\n");
- return ret;
- }
- ret = ci_enable_didt(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_didt failed\n");
- return ret;
- }
- ret = ci_enable_smc_cac(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_smc_cac failed\n");
- return ret;
- }
- ret = ci_enable_power_containment(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_power_containment failed\n");
- return ret;
- }
-
- ret = ci_power_control_set_level(adev);
- if (ret) {
- DRM_ERROR("ci_power_control_set_level failed\n");
- return ret;
- }
-
- ci_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
-
- ret = ci_enable_thermal_based_sclk_dpm(adev, true);
- if (ret) {
- DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n");
- return ret;
- }
-
- ci_thermal_start_thermal_controller(adev);
-
- ci_update_current_ps(adev, boot_ps);
-
- return 0;
-}
-
-static void ci_dpm_disable(struct amdgpu_device *adev)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
-
- amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
- AMDGPU_THERMAL_IRQ_LOW_TO_HIGH);
- amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
- AMDGPU_THERMAL_IRQ_HIGH_TO_LOW);
-
- ci_dpm_powergate_uvd(adev, true);
-
- if (!amdgpu_ci_is_smc_running(adev))
- return;
-
- ci_thermal_stop_thermal_controller(adev);
-
- if (pi->thermal_protection)
- ci_enable_thermal_protection(adev, false);
- ci_enable_power_containment(adev, false);
- ci_enable_smc_cac(adev, false);
- ci_enable_didt(adev, false);
- ci_enable_spread_spectrum(adev, false);
- ci_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
- ci_stop_dpm(adev);
- ci_enable_ds_master_switch(adev, false);
- ci_enable_ulv(adev, false);
- ci_clear_vc(adev);
- ci_reset_to_default(adev);
- ci_dpm_stop_smc(adev);
- ci_force_switch_to_arb_f0(adev);
- ci_enable_thermal_based_sclk_dpm(adev, false);
-
- ci_update_current_ps(adev, boot_ps);
-}
-
-static int ci_dpm_set_power_state(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps *new_ps = &pi->requested_rps;
- struct amdgpu_ps *old_ps = &pi->current_rps;
- int ret;
-
- ci_find_dpm_states_clocks_in_dpm_table(adev, new_ps);
- if (pi->pcie_performance_request)
- ci_request_link_speed_change_before_state_change(adev, new_ps, old_ps);
- ret = ci_freeze_sclk_mclk_dpm(adev);
- if (ret) {
- DRM_ERROR("ci_freeze_sclk_mclk_dpm failed\n");
- return ret;
- }
- ret = ci_populate_and_upload_sclk_mclk_dpm_levels(adev, new_ps);
- if (ret) {
- DRM_ERROR("ci_populate_and_upload_sclk_mclk_dpm_levels failed\n");
- return ret;
- }
- ret = ci_generate_dpm_level_enable_mask(adev, new_ps);
- if (ret) {
- DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
- return ret;
- }
-
- ret = ci_update_vce_dpm(adev, new_ps, old_ps);
- if (ret) {
- DRM_ERROR("ci_update_vce_dpm failed\n");
- return ret;
- }
-
- ret = ci_update_sclk_t(adev);
- if (ret) {
- DRM_ERROR("ci_update_sclk_t failed\n");
- return ret;
- }
- if (pi->caps_dynamic_ac_timing) {
- ret = ci_update_and_upload_mc_reg_table(adev);
- if (ret) {
- DRM_ERROR("ci_update_and_upload_mc_reg_table failed\n");
- return ret;
- }
- }
- ret = ci_program_memory_timing_parameters(adev);
- if (ret) {
- DRM_ERROR("ci_program_memory_timing_parameters failed\n");
- return ret;
- }
- ret = ci_unfreeze_sclk_mclk_dpm(adev);
- if (ret) {
- DRM_ERROR("ci_unfreeze_sclk_mclk_dpm failed\n");
- return ret;
- }
- ret = ci_upload_dpm_level_enable_mask(adev);
- if (ret) {
- DRM_ERROR("ci_upload_dpm_level_enable_mask failed\n");
- return ret;
- }
- if (pi->pcie_performance_request)
- ci_notify_link_speed_change_after_state_change(adev, new_ps, old_ps);
-
- return 0;
-}
-
-#if 0
-static void ci_dpm_reset_asic(struct amdgpu_device *adev)
-{
- ci_set_boot_state(adev);
-}
-#endif
-
-static void ci_dpm_display_configuration_changed(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- ci_program_display_gap(adev);
-}
-
-union power_info {
- struct _ATOM_POWERPLAY_INFO info;
- struct _ATOM_POWERPLAY_INFO_V2 info_2;
- struct _ATOM_POWERPLAY_INFO_V3 info_3;
- struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
- struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
- struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
-};
-
-union pplib_clock_info {
- struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
- struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
- struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
- struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
- struct _ATOM_PPLIB_SI_CLOCK_INFO si;
- struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
-};
-
-union pplib_power_state {
- struct _ATOM_PPLIB_STATE v1;
- struct _ATOM_PPLIB_STATE_V2 v2;
-};
-
-static void ci_parse_pplib_non_clock_info(struct amdgpu_device *adev,
- struct amdgpu_ps *rps,
- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
- u8 table_rev)
-{
- rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
- rps->class = le16_to_cpu(non_clock_info->usClassification);
- rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
-
- if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
- rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
- rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
- } else {
- rps->vclk = 0;
- rps->dclk = 0;
- }
-
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
- adev->pm.dpm.boot_ps = rps;
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
- adev->pm.dpm.uvd_ps = rps;
-}
-
-static void ci_parse_pplib_clock_info(struct amdgpu_device *adev,
- struct amdgpu_ps *rps, int index,
- union pplib_clock_info *clock_info)
-{
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *ps = ci_get_ps(rps);
- struct ci_pl *pl = &ps->performance_levels[index];
-
- ps->performance_level_count = index + 1;
-
- pl->sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
- pl->sclk |= clock_info->ci.ucEngineClockHigh << 16;
- pl->mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
- pl->mclk |= clock_info->ci.ucMemoryClockHigh << 16;
-
- pl->pcie_gen = amdgpu_get_pcie_gen_support(adev,
- pi->sys_pcie_mask,
- pi->vbios_boot_state.pcie_gen_bootup_value,
- clock_info->ci.ucPCIEGen);
- pl->pcie_lane = amdgpu_get_pcie_lane_support(adev,
- pi->vbios_boot_state.pcie_lane_bootup_value,
- le16_to_cpu(clock_info->ci.usPCIELane));
-
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
- pi->acpi_pcie_gen = pl->pcie_gen;
- }
-
- if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
- pi->ulv.supported = true;
- pi->ulv.pl = *pl;
- pi->ulv.cg_ulv_parameter = CISLANDS_CGULVPARAMETER_DFLT;
- }
-
- /* patch up boot state */
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
- pl->mclk = pi->vbios_boot_state.mclk_bootup_value;
- pl->sclk = pi->vbios_boot_state.sclk_bootup_value;
- pl->pcie_gen = pi->vbios_boot_state.pcie_gen_bootup_value;
- pl->pcie_lane = pi->vbios_boot_state.pcie_lane_bootup_value;
- }
-
- switch (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
- case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
- pi->use_pcie_powersaving_levels = true;
- if (pi->pcie_gen_powersaving.max < pl->pcie_gen)
- pi->pcie_gen_powersaving.max = pl->pcie_gen;
- if (pi->pcie_gen_powersaving.min > pl->pcie_gen)
- pi->pcie_gen_powersaving.min = pl->pcie_gen;
- if (pi->pcie_lane_powersaving.max < pl->pcie_lane)
- pi->pcie_lane_powersaving.max = pl->pcie_lane;
- if (pi->pcie_lane_powersaving.min > pl->pcie_lane)
- pi->pcie_lane_powersaving.min = pl->pcie_lane;
- break;
- case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
- pi->use_pcie_performance_levels = true;
- if (pi->pcie_gen_performance.max < pl->pcie_gen)
- pi->pcie_gen_performance.max = pl->pcie_gen;
- if (pi->pcie_gen_performance.min > pl->pcie_gen)
- pi->pcie_gen_performance.min = pl->pcie_gen;
- if (pi->pcie_lane_performance.max < pl->pcie_lane)
- pi->pcie_lane_performance.max = pl->pcie_lane;
- if (pi->pcie_lane_performance.min > pl->pcie_lane)
- pi->pcie_lane_performance.min = pl->pcie_lane;
- break;
- default:
- break;
- }
-}
-
-static int ci_parse_power_table(struct amdgpu_device *adev)
-{
- struct amdgpu_mode_info *mode_info = &adev->mode_info;
- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
- union pplib_power_state *power_state;
- int i, j, k, non_clock_array_index, clock_array_index;
- union pplib_clock_info *clock_info;
- struct _StateArray *state_array;
- struct _ClockInfoArray *clock_info_array;
- struct _NonClockInfoArray *non_clock_info_array;
- union power_info *power_info;
- int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
- u16 data_offset;
- u8 frev, crev;
- u8 *power_state_offset;
- struct ci_ps *ps;
-
- if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
- &frev, &crev, &data_offset))
- return -EINVAL;
- power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
-
- amdgpu_add_thermal_controller(adev);
-
- state_array = (struct _StateArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usStateArrayOffset));
- clock_info_array = (struct _ClockInfoArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
- non_clock_info_array = (struct _NonClockInfoArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
-
- adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
- sizeof(struct amdgpu_ps),
- GFP_KERNEL);
- if (!adev->pm.dpm.ps)
- return -ENOMEM;
- power_state_offset = (u8 *)state_array->states;
- for (i = 0; i < state_array->ucNumEntries; i++) {
- u8 *idx;
- power_state = (union pplib_power_state *)power_state_offset;
- non_clock_array_index = power_state->v2.nonClockInfoIndex;
- non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
- &non_clock_info_array->nonClockInfo[non_clock_array_index];
- ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
- if (ps == NULL) {
- kfree(adev->pm.dpm.ps);
- return -ENOMEM;
- }
- adev->pm.dpm.ps[i].ps_priv = ps;
- ci_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
- non_clock_info,
- non_clock_info_array->ucEntrySize);
- k = 0;
- idx = (u8 *)&power_state->v2.clockInfoIndex[0];
- for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
- clock_array_index = idx[j];
- if (clock_array_index >= clock_info_array->ucNumEntries)
- continue;
- if (k >= CISLANDS_MAX_HARDWARE_POWERLEVELS)
- break;
- clock_info = (union pplib_clock_info *)
- ((u8 *)&clock_info_array->clockInfo[0] +
- (clock_array_index * clock_info_array->ucEntrySize));
- ci_parse_pplib_clock_info(adev,
- &adev->pm.dpm.ps[i], k,
- clock_info);
- k++;
- }
- power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
- }
- adev->pm.dpm.num_ps = state_array->ucNumEntries;
-
- /* fill in the vce power states */
- for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) {
- u32 sclk, mclk;
- clock_array_index = adev->pm.dpm.vce_states[i].clk_idx;
- clock_info = (union pplib_clock_info *)
- &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
- sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
- sclk |= clock_info->ci.ucEngineClockHigh << 16;
- mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
- mclk |= clock_info->ci.ucMemoryClockHigh << 16;
- adev->pm.dpm.vce_states[i].sclk = sclk;
- adev->pm.dpm.vce_states[i].mclk = mclk;
- }
-
- return 0;
-}
-
-static int ci_get_vbios_boot_values(struct amdgpu_device *adev,
- struct ci_vbios_boot_state *boot_state)
-{
- struct amdgpu_mode_info *mode_info = &adev->mode_info;
- int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
- ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
- u8 frev, crev;
- u16 data_offset;
-
- if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
- &frev, &crev, &data_offset)) {
- firmware_info =
- (ATOM_FIRMWARE_INFO_V2_2 *)(mode_info->atom_context->bios +
- data_offset);
- boot_state->mvdd_bootup_value = le16_to_cpu(firmware_info->usBootUpMVDDCVoltage);
- boot_state->vddc_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCVoltage);
- boot_state->vddci_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCIVoltage);
- boot_state->pcie_gen_bootup_value = ci_get_current_pcie_speed(adev);
- boot_state->pcie_lane_bootup_value = ci_get_current_pcie_lane_number(adev);
- boot_state->sclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultEngineClock);
- boot_state->mclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultMemoryClock);
-
- return 0;
- }
- return -EINVAL;
-}
-
-static void ci_dpm_fini(struct amdgpu_device *adev)
-{
- int i;
-
- for (i = 0; i < adev->pm.dpm.num_ps; i++) {
- kfree(adev->pm.dpm.ps[i].ps_priv);
- }
- kfree(adev->pm.dpm.ps);
- kfree(adev->pm.dpm.priv);
- kfree(adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
- amdgpu_free_extended_power_table(adev);
-}
-
-/**
- * ci_dpm_init_microcode - load ucode images from disk
- *
- * @adev: amdgpu_device pointer
- *
- * Use the firmware interface to load the ucode images into
- * the driver (not loaded into hw).
- * Returns 0 on success, error on failure.
- */
-static int ci_dpm_init_microcode(struct amdgpu_device *adev)
-{
- const char *chip_name;
- char fw_name[30];
- int err;
-
- DRM_DEBUG("\n");
-
- switch (adev->asic_type) {
- case CHIP_BONAIRE:
- if ((adev->pdev->revision == 0x80) ||
- (adev->pdev->revision == 0x81) ||
- (adev->pdev->device == 0x665f))
- chip_name = "bonaire_k";
- else
- chip_name = "bonaire";
- break;
- case CHIP_HAWAII:
- if (adev->pdev->revision == 0x80)
- chip_name = "hawaii_k";
- else
- chip_name = "hawaii";
- break;
- case CHIP_KAVERI:
- case CHIP_KABINI:
- case CHIP_MULLINS:
- default: BUG();
- }
-
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name);
- err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->pm.fw);
-
-out:
- if (err) {
- pr_err("cik_smc: Failed to load firmware \"%s\"\n", fw_name);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
- }
- return err;
-}
-
-static int ci_dpm_init(struct amdgpu_device *adev)
-{
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- SMU7_Discrete_DpmTable *dpm_table;
- struct amdgpu_gpio_rec gpio;
- u16 data_offset, size;
- u8 frev, crev;
- struct ci_power_info *pi;
- int ret;
-
- pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
- if (pi == NULL)
- return -ENOMEM;
- adev->pm.dpm.priv = pi;
-
- pi->sys_pcie_mask =
- adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK;
-
- pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
-
- pi->pcie_gen_performance.max = AMDGPU_PCIE_GEN1;
- pi->pcie_gen_performance.min = AMDGPU_PCIE_GEN3;
- pi->pcie_gen_powersaving.max = AMDGPU_PCIE_GEN1;
- pi->pcie_gen_powersaving.min = AMDGPU_PCIE_GEN3;
-
- pi->pcie_lane_performance.max = 0;
- pi->pcie_lane_performance.min = 16;
- pi->pcie_lane_powersaving.max = 0;
- pi->pcie_lane_powersaving.min = 16;
-
- ret = ci_get_vbios_boot_values(adev, &pi->vbios_boot_state);
- if (ret) {
- ci_dpm_fini(adev);
- return ret;
- }
-
- ret = amdgpu_get_platform_caps(adev);
- if (ret) {
- ci_dpm_fini(adev);
- return ret;
- }
-
- ret = amdgpu_parse_extended_power_table(adev);
- if (ret) {
- ci_dpm_fini(adev);
- return ret;
- }
-
- ret = ci_parse_power_table(adev);
- if (ret) {
- ci_dpm_fini(adev);
- return ret;
- }
-
- pi->dll_default_on = false;
- pi->sram_end = SMC_RAM_END;
-
- pi->activity_target[0] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[1] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[2] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[3] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[4] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[5] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[6] = CISLAND_TARGETACTIVITY_DFLT;
- pi->activity_target[7] = CISLAND_TARGETACTIVITY_DFLT;
-
- pi->mclk_activity_target = CISLAND_MCLK_TARGETACTIVITY_DFLT;
-
- pi->sclk_dpm_key_disabled = 0;
- pi->mclk_dpm_key_disabled = 0;
- pi->pcie_dpm_key_disabled = 0;
- pi->thermal_sclk_dpm_enabled = 0;
-
- if (adev->powerplay.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)
- pi->caps_sclk_ds = true;
- else
- pi->caps_sclk_ds = false;
-
- pi->mclk_strobe_mode_threshold = 40000;
- pi->mclk_stutter_mode_threshold = 40000;
- pi->mclk_edc_enable_threshold = 40000;
- pi->mclk_edc_wr_enable_threshold = 40000;
-
- ci_initialize_powertune_defaults(adev);
-
- pi->caps_fps = false;
-
- pi->caps_sclk_throttle_low_notification = false;
-
- pi->caps_uvd_dpm = true;
- pi->caps_vce_dpm = true;
-
- ci_get_leakage_voltages(adev);
- ci_patch_dependency_tables_with_leakage(adev);
- ci_set_private_data_variables_based_on_pptable(adev);
-
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
- kcalloc(4,
- sizeof(struct amdgpu_clock_voltage_dependency_entry),
- GFP_KERNEL);
- if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
- ci_dpm_fini(adev);
- return -ENOMEM;
- }
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
- adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
-
- adev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
- adev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
- adev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
-
- adev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
- adev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
- adev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
- adev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
-
- if (adev->asic_type == CHIP_HAWAII) {
- pi->thermal_temp_setting.temperature_low = 94500;
- pi->thermal_temp_setting.temperature_high = 95000;
- pi->thermal_temp_setting.temperature_shutdown = 104000;
- } else {
- pi->thermal_temp_setting.temperature_low = 99500;
- pi->thermal_temp_setting.temperature_high = 100000;
- pi->thermal_temp_setting.temperature_shutdown = 104000;
- }
-
- pi->uvd_enabled = false;
-
- dpm_table = &pi->smc_state_table;
-
- gpio = amdgpu_atombios_lookup_gpio(adev, VDDC_VRHOT_GPIO_PINID);
- if (gpio.valid) {
- dpm_table->VRHotGpio = gpio.shift;
- adev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
- } else {
- dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN;
- adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
- }
-
- gpio = amdgpu_atombios_lookup_gpio(adev, PP_AC_DC_SWITCH_GPIO_PINID);
- if (gpio.valid) {
- dpm_table->AcDcGpio = gpio.shift;
- adev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC;
- } else {
- dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN;
- adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC;
- }
-
- gpio = amdgpu_atombios_lookup_gpio(adev, VDDC_PCC_GPIO_PINID);
- if (gpio.valid) {
- u32 tmp = RREG32_SMC(ixCNB_PWRMGT_CNTL);
-
- switch (gpio.shift) {
- case 0:
- tmp &= ~CNB_PWRMGT_CNTL__GNB_SLOW_MODE_MASK;
- tmp |= 1 << CNB_PWRMGT_CNTL__GNB_SLOW_MODE__SHIFT;
- break;
- case 1:
- tmp &= ~CNB_PWRMGT_CNTL__GNB_SLOW_MODE_MASK;
- tmp |= 2 << CNB_PWRMGT_CNTL__GNB_SLOW_MODE__SHIFT;
- break;
- case 2:
- tmp |= CNB_PWRMGT_CNTL__GNB_SLOW_MASK;
- break;
- case 3:
- tmp |= CNB_PWRMGT_CNTL__FORCE_NB_PS1_MASK;
- break;
- case 4:
- tmp |= CNB_PWRMGT_CNTL__DPM_ENABLED_MASK;
- break;
- default:
- DRM_INFO("Invalid PCC GPIO: %u!\n", gpio.shift);
- break;
- }
- WREG32_SMC(ixCNB_PWRMGT_CNTL, tmp);
- }
-
- pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE;
- pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE;
- pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE;
- if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
- pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
- else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
- pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
-
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL) {
- if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
- pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
- else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
- pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
- else
- adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL;
- }
-
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL) {
- if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
- pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
- else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
- pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
- else
- adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_MVDDCONTROL;
- }
-
- pi->vddc_phase_shed_control = true;
-
-#if defined(CONFIG_ACPI)
- pi->pcie_performance_request =
- amdgpu_acpi_is_pcie_performance_request_supported(adev);
-#else
- pi->pcie_performance_request = false;
-#endif
-
- if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->caps_sclk_ss_support = true;
- pi->caps_mclk_ss_support = true;
- pi->dynamic_ss = true;
- } else {
- pi->caps_sclk_ss_support = false;
- pi->caps_mclk_ss_support = false;
- pi->dynamic_ss = true;
- }
-
- if (adev->pm.int_thermal_type != THERMAL_TYPE_NONE)
- pi->thermal_protection = true;
- else
- pi->thermal_protection = false;
-
- pi->caps_dynamic_ac_timing = true;
-
- pi->uvd_power_gated = true;
-
- /* make sure dc limits are valid */
- if ((adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
- (adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0))
- adev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
-
- pi->fan_ctrl_is_in_default_mode = true;
-
- return 0;
-}
-
-static void
-ci_dpm_debugfs_print_current_performance_level(void *handle,
- struct seq_file *m)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct amdgpu_ps *rps = &pi->current_rps;
- u32 sclk = ci_get_average_sclk_freq(adev);
- u32 mclk = ci_get_average_mclk_freq(adev);
- u32 activity_percent = 50;
- int ret;
-
- ret = ci_read_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, AverageGraphicsA),
- &activity_percent);
-
- if (ret == 0) {
- activity_percent += 0x80;
- activity_percent >>= 8;
- activity_percent = activity_percent > 100 ? 100 : activity_percent;
- }
-
- seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en");
- seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
- seq_printf(m, "power level avg sclk: %u mclk: %u\n",
- sclk, mclk);
- seq_printf(m, "GPU load: %u %%\n", activity_percent);
-}
-
-static void ci_dpm_print_power_state(void *handle, void *current_ps)
-{
- struct amdgpu_ps *rps = (struct amdgpu_ps *)current_ps;
- struct ci_ps *ps = ci_get_ps(rps);
- struct ci_pl *pl;
- int i;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- amdgpu_dpm_print_class_info(rps->class, rps->class2);
- amdgpu_dpm_print_cap_info(rps->caps);
- printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
- for (i = 0; i < ps->performance_level_count; i++) {
- pl = &ps->performance_levels[i];
- printk("\t\tpower level %d sclk: %u mclk: %u pcie gen: %u pcie lanes: %u\n",
- i, pl->sclk, pl->mclk, pl->pcie_gen + 1, pl->pcie_lane);
- }
- amdgpu_dpm_print_ps_status(adev, rps);
-}
-
-static inline bool ci_are_power_levels_equal(const struct ci_pl *ci_cpl1,
- const struct ci_pl *ci_cpl2)
-{
- return ((ci_cpl1->mclk == ci_cpl2->mclk) &&
- (ci_cpl1->sclk == ci_cpl2->sclk) &&
- (ci_cpl1->pcie_gen == ci_cpl2->pcie_gen) &&
- (ci_cpl1->pcie_lane == ci_cpl2->pcie_lane));
-}
-
-static int ci_check_state_equal(void *handle,
- void *current_ps,
- void *request_ps,
- bool *equal)
-{
- struct ci_ps *ci_cps;
- struct ci_ps *ci_rps;
- int i;
- struct amdgpu_ps *cps = (struct amdgpu_ps *)current_ps;
- struct amdgpu_ps *rps = (struct amdgpu_ps *)request_ps;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev == NULL || cps == NULL || rps == NULL || equal == NULL)
- return -EINVAL;
-
- ci_cps = ci_get_ps((struct amdgpu_ps *)cps);
- ci_rps = ci_get_ps((struct amdgpu_ps *)rps);
-
- if (ci_cps == NULL) {
- *equal = false;
- return 0;
- }
-
- if (ci_cps->performance_level_count != ci_rps->performance_level_count) {
-
- *equal = false;
- return 0;
- }
-
- for (i = 0; i < ci_cps->performance_level_count; i++) {
- if (!ci_are_power_levels_equal(&(ci_cps->performance_levels[i]),
- &(ci_rps->performance_levels[i]))) {
- *equal = false;
- return 0;
- }
- }
-
- /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
- *equal = ((cps->vclk == rps->vclk) && (cps->dclk == rps->dclk));
- *equal &= ((cps->evclk == rps->evclk) && (cps->ecclk == rps->ecclk));
-
- return 0;
-}
-
-static u32 ci_dpm_get_sclk(void *handle, bool low)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
-
- if (low)
- return requested_state->performance_levels[0].sclk;
- else
- return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
-}
-
-static u32 ci_dpm_get_mclk(void *handle, bool low)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
-
- if (low)
- return requested_state->performance_levels[0].mclk;
- else
- return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
-}
-
-/* get temperature in millidegrees */
-static int ci_dpm_get_temp(void *handle)
-{
- u32 temp;
- int actual_temp = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- temp = (RREG32_SMC(ixCG_MULT_THERMAL_STATUS) & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
- CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
-
- if (temp & 0x200)
- actual_temp = 255;
- else
- actual_temp = temp & 0x1ff;
-
- actual_temp = actual_temp * 1000;
-
- return actual_temp;
-}
-
-static int ci_set_temperature_range(struct amdgpu_device *adev)
-{
- int ret;
-
- ret = ci_thermal_enable_alert(adev, false);
- if (ret)
- return ret;
- ret = ci_thermal_set_temperature_range(adev, CISLANDS_TEMP_RANGE_MIN,
- CISLANDS_TEMP_RANGE_MAX);
- if (ret)
- return ret;
- ret = ci_thermal_enable_alert(adev, true);
- if (ret)
- return ret;
- return ret;
-}
-
-static int ci_dpm_early_init(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- adev->powerplay.pp_funcs = &ci_dpm_funcs;
- adev->powerplay.pp_handle = adev;
- ci_dpm_set_irq_funcs(adev);
-
- return 0;
-}
-
-static int ci_dpm_late_init(void *handle)
-{
- int ret;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (!adev->pm.dpm_enabled)
- return 0;
-
- /* init the sysfs and debugfs files late */
- ret = amdgpu_pm_sysfs_init(adev);
- if (ret)
- return ret;
-
- ret = ci_set_temperature_range(adev);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int ci_dpm_sw_init(void *handle)
-{
- int ret;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- ret = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 230,
- &adev->pm.dpm.thermal.irq);
- if (ret)
- return ret;
-
- ret = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 231,
- &adev->pm.dpm.thermal.irq);
- if (ret)
- return ret;
-
- /* default to balanced state */
- adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.forced_level = AMD_DPM_FORCED_LEVEL_AUTO;
- adev->pm.default_sclk = adev->clock.default_sclk;
- adev->pm.default_mclk = adev->clock.default_mclk;
- adev->pm.current_sclk = adev->clock.default_sclk;
- adev->pm.current_mclk = adev->clock.default_mclk;
- adev->pm.int_thermal_type = THERMAL_TYPE_NONE;
-
- ret = ci_dpm_init_microcode(adev);
- if (ret)
- return ret;
-
- if (amdgpu_dpm == 0)
- return 0;
-
- INIT_WORK(&adev->pm.dpm.thermal.work, amdgpu_dpm_thermal_work_handler);
- mutex_lock(&adev->pm.mutex);
- ret = ci_dpm_init(adev);
- if (ret)
- goto dpm_failed;
- adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
- if (amdgpu_dpm == 1)
- amdgpu_pm_print_power_states(adev);
- mutex_unlock(&adev->pm.mutex);
- DRM_INFO("amdgpu: dpm initialized\n");
-
- return 0;
-
-dpm_failed:
- ci_dpm_fini(adev);
- mutex_unlock(&adev->pm.mutex);
- DRM_ERROR("amdgpu: dpm initialization failed\n");
- return ret;
-}
-
-static int ci_dpm_sw_fini(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- flush_work(&adev->pm.dpm.thermal.work);
-
- mutex_lock(&adev->pm.mutex);
- ci_dpm_fini(adev);
- mutex_unlock(&adev->pm.mutex);
-
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
-
- return 0;
-}
-
-static int ci_dpm_hw_init(void *handle)
-{
- int ret;
-
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (!amdgpu_dpm) {
- ret = ci_upload_firmware(adev);
- if (ret) {
- DRM_ERROR("ci_upload_firmware failed\n");
- return ret;
- }
- ci_dpm_start_smc(adev);
- return 0;
- }
-
- mutex_lock(&adev->pm.mutex);
- ci_dpm_setup_asic(adev);
- ret = ci_dpm_enable(adev);
- if (ret)
- adev->pm.dpm_enabled = false;
- else
- adev->pm.dpm_enabled = true;
- mutex_unlock(&adev->pm.mutex);
-
- return ret;
-}
-
-static int ci_dpm_hw_fini(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->pm.dpm_enabled) {
- mutex_lock(&adev->pm.mutex);
- ci_dpm_disable(adev);
- mutex_unlock(&adev->pm.mutex);
- } else {
- ci_dpm_stop_smc(adev);
- }
-
- return 0;
-}
-
-static int ci_dpm_suspend(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->pm.dpm_enabled) {
- mutex_lock(&adev->pm.mutex);
- amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
- AMDGPU_THERMAL_IRQ_LOW_TO_HIGH);
- amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
- AMDGPU_THERMAL_IRQ_HIGH_TO_LOW);
- adev->pm.dpm.last_user_state = adev->pm.dpm.user_state;
- adev->pm.dpm.last_state = adev->pm.dpm.state;
- adev->pm.dpm.user_state = POWER_STATE_TYPE_INTERNAL_BOOT;
- adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_BOOT;
- mutex_unlock(&adev->pm.mutex);
- amdgpu_pm_compute_clocks(adev);
-
- }
-
- return 0;
-}
-
-static int ci_dpm_resume(void *handle)
-{
- int ret;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->pm.dpm_enabled) {
- /* asic init will reset to the boot state */
- mutex_lock(&adev->pm.mutex);
- ci_dpm_setup_asic(adev);
- ret = ci_dpm_enable(adev);
- if (ret)
- adev->pm.dpm_enabled = false;
- else
- adev->pm.dpm_enabled = true;
- adev->pm.dpm.user_state = adev->pm.dpm.last_user_state;
- adev->pm.dpm.state = adev->pm.dpm.last_state;
- mutex_unlock(&adev->pm.mutex);
- if (adev->pm.dpm_enabled)
- amdgpu_pm_compute_clocks(adev);
- }
- return 0;
-}
-
-static bool ci_dpm_is_idle(void *handle)
-{
- /* XXX */
- return true;
-}
-
-static int ci_dpm_wait_for_idle(void *handle)
-{
- /* XXX */
- return 0;
-}
-
-static int ci_dpm_soft_reset(void *handle)
-{
- return 0;
-}
-
-static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
- struct amdgpu_irq_src *source,
- unsigned type,
- enum amdgpu_interrupt_state state)
-{
- u32 cg_thermal_int;
-
- switch (type) {
- case AMDGPU_THERMAL_IRQ_LOW_TO_HIGH:
- switch (state) {
- case AMDGPU_IRQ_STATE_DISABLE:
- cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
- WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
- break;
- case AMDGPU_IRQ_STATE_ENABLE:
- cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
- WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
- break;
- default:
- break;
- }
- break;
-
- case AMDGPU_THERMAL_IRQ_HIGH_TO_LOW:
- switch (state) {
- case AMDGPU_IRQ_STATE_DISABLE:
- cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
- WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
- break;
- case AMDGPU_IRQ_STATE_ENABLE:
- cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
- WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
- break;
- default:
- break;
- }
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-static int ci_dpm_process_interrupt(struct amdgpu_device *adev,
- struct amdgpu_irq_src *source,
- struct amdgpu_iv_entry *entry)
-{
- bool queue_thermal = false;
-
- if (entry == NULL)
- return -EINVAL;
-
- switch (entry->src_id) {
- case 230: /* thermal low to high */
- DRM_DEBUG("IH: thermal low to high\n");
- adev->pm.dpm.thermal.high_to_low = false;
- queue_thermal = true;
- break;
- case 231: /* thermal high to low */
- DRM_DEBUG("IH: thermal high to low\n");
- adev->pm.dpm.thermal.high_to_low = true;
- queue_thermal = true;
- break;
- default:
- break;
- }
-
- if (queue_thermal)
- schedule_work(&adev->pm.dpm.thermal.work);
-
- return 0;
-}
-
-static int ci_dpm_set_clockgating_state(void *handle,
- enum amd_clockgating_state state)
-{
- return 0;
-}
-
-static int ci_dpm_set_powergating_state(void *handle,
- enum amd_powergating_state state)
-{
- return 0;
-}
-
-static int ci_dpm_print_clock_levels(void *handle,
- enum pp_clock_type type, char *buf)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
- struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
- struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
-
- int i, now, size = 0;
- uint32_t clock, pcie_speed;
-
- switch (type) {
- case PP_SCLK:
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetSclkFrequency);
- clock = RREG32(mmSMC_MSG_ARG_0);
-
- for (i = 0; i < sclk_table->count; i++) {
- if (clock > sclk_table->dpm_levels[i].value)
- continue;
- break;
- }
- now = i;
-
- for (i = 0; i < sclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, sclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
- break;
- case PP_MCLK:
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetMclkFrequency);
- clock = RREG32(mmSMC_MSG_ARG_0);
-
- for (i = 0; i < mclk_table->count; i++) {
- if (clock > mclk_table->dpm_levels[i].value)
- continue;
- break;
- }
- now = i;
-
- for (i = 0; i < mclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, mclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
- break;
- case PP_PCIE:
- pcie_speed = ci_get_current_pcie_speed(adev);
- for (i = 0; i < pcie_table->count; i++) {
- if (pcie_speed != pcie_table->dpm_levels[i].value)
- continue;
- break;
- }
- now = i;
-
- for (i = 0; i < pcie_table->count; i++)
- size += sprintf(buf + size, "%d: %s %s\n", i,
- (pcie_table->dpm_levels[i].value == 0) ? "2.5GT/s, x1" :
- (pcie_table->dpm_levels[i].value == 1) ? "5.0GT/s, x16" :
- (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "",
- (i == now) ? "*" : "");
- break;
- default:
- break;
- }
-
- return size;
-}
-
-static int ci_dpm_force_clock_level(void *handle,
- enum pp_clock_type type, uint32_t mask)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
-
- if (adev->pm.dpm.forced_level != AMD_DPM_FORCED_LEVEL_MANUAL)
- return -EINVAL;
-
- if (mask == 0)
- return -EINVAL;
-
- switch (type) {
- case PP_SCLK:
- if (!pi->sclk_dpm_key_disabled)
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
- break;
-
- case PP_MCLK:
- if (!pi->mclk_dpm_key_disabled)
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_MCLKDPM_SetEnabledMask,
- pi->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
- break;
-
- case PP_PCIE:
- {
- uint32_t tmp = mask & pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
-
- if (!pi->pcie_dpm_key_disabled) {
- if (fls(tmp) != ffs(tmp))
- amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_UnForceLevel);
- else
- amdgpu_ci_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_PCIeDPM_ForceLevel,
- fls(tmp) - 1);
- }
- break;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-static int ci_dpm_get_sclk_od(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_single_dpm_table *sclk_table = &(pi->dpm_table.sclk_table);
- struct ci_single_dpm_table *golden_sclk_table =
- &(pi->golden_dpm_table.sclk_table);
- int value;
-
- value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
- golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
- 100 /
- golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
- return value;
-}
-
-static int ci_dpm_set_sclk_od(void *handle, uint32_t value)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *ps = ci_get_ps(adev->pm.dpm.requested_ps);
- struct ci_single_dpm_table *golden_sclk_table =
- &(pi->golden_dpm_table.sclk_table);
-
- if (value > 20)
- value = 20;
-
- ps->performance_levels[ps->performance_level_count - 1].sclk =
- golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
- value / 100 +
- golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
- return 0;
-}
-
-static int ci_dpm_get_mclk_od(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_single_dpm_table *mclk_table = &(pi->dpm_table.mclk_table);
- struct ci_single_dpm_table *golden_mclk_table =
- &(pi->golden_dpm_table.mclk_table);
- int value;
-
- value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
- golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
- 100 /
- golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
- return value;
-}
-
-static int ci_dpm_set_mclk_od(void *handle, uint32_t value)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- struct ci_power_info *pi = ci_get_pi(adev);
- struct ci_ps *ps = ci_get_ps(adev->pm.dpm.requested_ps);
- struct ci_single_dpm_table *golden_mclk_table =
- &(pi->golden_dpm_table.mclk_table);
-
- if (value > 20)
- value = 20;
-
- ps->performance_levels[ps->performance_level_count - 1].mclk =
- golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
- value / 100 +
- golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
- return 0;
-}
-
-static int ci_dpm_read_sensor(void *handle, int idx,
- void *value, int *size)
-{
- u32 activity_percent = 50;
- int ret;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- /* size must be at least 4 bytes for all sensors */
- if (*size < 4)
- return -EINVAL;
-
- switch (idx) {
- case AMDGPU_PP_SENSOR_GFX_SCLK:
- *((uint32_t *)value) = ci_get_average_sclk_freq(adev);
- *size = 4;
- return 0;
- case AMDGPU_PP_SENSOR_GFX_MCLK:
- *((uint32_t *)value) = ci_get_average_mclk_freq(adev);
- *size = 4;
- return 0;
- case AMDGPU_PP_SENSOR_GPU_TEMP:
- *((uint32_t *)value) = ci_dpm_get_temp(adev);
- *size = 4;
- return 0;
- case AMDGPU_PP_SENSOR_GPU_LOAD:
- ret = ci_read_smc_soft_register(adev,
- offsetof(SMU7_SoftRegisters,
- AverageGraphicsA),
- &activity_percent);
- if (ret == 0) {
- activity_percent += 0x80;
- activity_percent >>= 8;
- activity_percent =
- activity_percent > 100 ? 100 : activity_percent;
- }
- *((uint32_t *)value) = activity_percent;
- *size = 4;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static int ci_set_powergating_by_smu(void *handle,
- uint32_t block_type, bool gate)
-{
- switch (block_type) {
- case AMD_IP_BLOCK_TYPE_UVD:
- ci_dpm_powergate_uvd(handle, gate);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static const struct amd_ip_funcs ci_dpm_ip_funcs = {
- .name = "ci_dpm",
- .early_init = ci_dpm_early_init,
- .late_init = ci_dpm_late_init,
- .sw_init = ci_dpm_sw_init,
- .sw_fini = ci_dpm_sw_fini,
- .hw_init = ci_dpm_hw_init,
- .hw_fini = ci_dpm_hw_fini,
- .suspend = ci_dpm_suspend,
- .resume = ci_dpm_resume,
- .is_idle = ci_dpm_is_idle,
- .wait_for_idle = ci_dpm_wait_for_idle,
- .soft_reset = ci_dpm_soft_reset,
- .set_clockgating_state = ci_dpm_set_clockgating_state,
- .set_powergating_state = ci_dpm_set_powergating_state,
-};
-
-const struct amdgpu_ip_block_version ci_smu_ip_block =
-{
- .type = AMD_IP_BLOCK_TYPE_SMC,
- .major = 7,
- .minor = 0,
- .rev = 0,
- .funcs = &ci_dpm_ip_funcs,
-};
-
-static const struct amd_pm_funcs ci_dpm_funcs = {
- .pre_set_power_state = &ci_dpm_pre_set_power_state,
- .set_power_state = &ci_dpm_set_power_state,
- .post_set_power_state = &ci_dpm_post_set_power_state,
- .display_configuration_changed = &ci_dpm_display_configuration_changed,
- .get_sclk = &ci_dpm_get_sclk,
- .get_mclk = &ci_dpm_get_mclk,
- .print_power_state = &ci_dpm_print_power_state,
- .debugfs_print_current_performance_level = &ci_dpm_debugfs_print_current_performance_level,
- .force_performance_level = &ci_dpm_force_performance_level,
- .vblank_too_short = &ci_dpm_vblank_too_short,
- .set_powergating_by_smu = &ci_set_powergating_by_smu,
- .set_fan_control_mode = &ci_dpm_set_fan_control_mode,
- .get_fan_control_mode = &ci_dpm_get_fan_control_mode,
- .set_fan_speed_percent = &ci_dpm_set_fan_speed_percent,
- .get_fan_speed_percent = &ci_dpm_get_fan_speed_percent,
- .print_clock_levels = ci_dpm_print_clock_levels,
- .force_clock_level = ci_dpm_force_clock_level,
- .get_sclk_od = ci_dpm_get_sclk_od,
- .set_sclk_od = ci_dpm_set_sclk_od,
- .get_mclk_od = ci_dpm_get_mclk_od,
- .set_mclk_od = ci_dpm_set_mclk_od,
- .check_state_equal = ci_check_state_equal,
- .get_vce_clock_state = amdgpu_get_vce_clock_state,
- .read_sensor = ci_dpm_read_sensor,
-};
-
-static const struct amdgpu_irq_src_funcs ci_dpm_irq_funcs = {
- .set = ci_dpm_set_interrupt_state,
- .process = ci_dpm_process_interrupt,
-};
-
-static void ci_dpm_set_irq_funcs(struct amdgpu_device *adev)
-{
- adev->pm.dpm.thermal.irq.num_types = AMDGPU_THERMAL_IRQ_LAST;
- adev->pm.dpm.thermal.irq.funcs = &ci_dpm_irq_funcs;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h
deleted file mode 100644
index 91be2996ae7c..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright 2013 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-#ifndef __CI_DPM_H__
-#define __CI_DPM_H__
-
-#include "amdgpu_atombios.h"
-#include "ppsmc.h"
-
-#define SMU__NUM_SCLK_DPM_STATE 8
-#define SMU__NUM_MCLK_DPM_LEVELS 6
-#define SMU__NUM_LCLK_DPM_LEVELS 8
-#define SMU__NUM_PCIE_DPM_LEVELS 8
-#include "smu7_discrete.h"
-
-#define CISLANDS_MAX_HARDWARE_POWERLEVELS 2
-
-#define CISLANDS_UNUSED_GPIO_PIN 0x7F
-
-struct ci_pl {
- u32 mclk;
- u32 sclk;
- enum amdgpu_pcie_gen pcie_gen;
- u16 pcie_lane;
-};
-
-struct ci_ps {
- u16 performance_level_count;
- bool dc_compatible;
- u32 sclk_t;
- struct ci_pl performance_levels[CISLANDS_MAX_HARDWARE_POWERLEVELS];
-};
-
-struct ci_dpm_level {
- bool enabled;
- u32 value;
- u32 param1;
-};
-
-#define CISLAND_MAX_DEEPSLEEP_DIVIDER_ID 5
-#define MAX_REGULAR_DPM_NUMBER 8
-#define CISLAND_MINIMUM_ENGINE_CLOCK 800
-
-struct ci_single_dpm_table {
- u32 count;
- struct ci_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
-};
-
-struct ci_dpm_table {
- struct ci_single_dpm_table sclk_table;
- struct ci_single_dpm_table mclk_table;
- struct ci_single_dpm_table pcie_speed_table;
- struct ci_single_dpm_table vddc_table;
- struct ci_single_dpm_table vddci_table;
- struct ci_single_dpm_table mvdd_table;
-};
-
-struct ci_mc_reg_entry {
- u32 mclk_max;
- u32 mc_data[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
-};
-
-struct ci_mc_reg_table {
- u8 last;
- u8 num_entries;
- u16 valid_flag;
- struct ci_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
- SMU7_Discrete_MCRegisterAddress mc_reg_address[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
-};
-
-struct ci_ulv_parm
-{
- bool supported;
- u32 cg_ulv_parameter;
- u32 volt_change_delay;
- struct ci_pl pl;
-};
-
-#define CISLANDS_MAX_LEAKAGE_COUNT 8
-
-struct ci_leakage_voltage {
- u16 count;
- u16 leakage_id[CISLANDS_MAX_LEAKAGE_COUNT];
- u16 actual_voltage[CISLANDS_MAX_LEAKAGE_COUNT];
-};
-
-struct ci_dpm_level_enable_mask {
- u32 uvd_dpm_enable_mask;
- u32 vce_dpm_enable_mask;
- u32 acp_dpm_enable_mask;
- u32 samu_dpm_enable_mask;
- u32 sclk_dpm_enable_mask;
- u32 mclk_dpm_enable_mask;
- u32 pcie_dpm_enable_mask;
-};
-
-struct ci_vbios_boot_state
-{
- u16 mvdd_bootup_value;
- u16 vddc_bootup_value;
- u16 vddci_bootup_value;
- u32 sclk_bootup_value;
- u32 mclk_bootup_value;
- u16 pcie_gen_bootup_value;
- u16 pcie_lane_bootup_value;
-};
-
-struct ci_clock_registers {
- u32 cg_spll_func_cntl;
- u32 cg_spll_func_cntl_2;
- u32 cg_spll_func_cntl_3;
- u32 cg_spll_func_cntl_4;
- u32 cg_spll_spread_spectrum;
- u32 cg_spll_spread_spectrum_2;
- u32 dll_cntl;
- u32 mclk_pwrmgt_cntl;
- u32 mpll_ad_func_cntl;
- u32 mpll_dq_func_cntl;
- u32 mpll_func_cntl;
- u32 mpll_func_cntl_1;
- u32 mpll_func_cntl_2;
- u32 mpll_ss1;
- u32 mpll_ss2;
-};
-
-struct ci_thermal_temperature_setting {
- s32 temperature_low;
- s32 temperature_high;
- s32 temperature_shutdown;
-};
-
-struct ci_pcie_perf_range {
- u16 max;
- u16 min;
-};
-
-enum ci_pt_config_reg_type {
- CISLANDS_CONFIGREG_MMR = 0,
- CISLANDS_CONFIGREG_SMC_IND,
- CISLANDS_CONFIGREG_DIDT_IND,
- CISLANDS_CONFIGREG_CACHE,
- CISLANDS_CONFIGREG_MAX
-};
-
-#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
-#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
-#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
-
-struct ci_pt_config_reg {
- u32 offset;
- u32 mask;
- u32 shift;
- u32 value;
- enum ci_pt_config_reg_type type;
-};
-
-struct ci_pt_defaults {
- u8 svi_load_line_en;
- u8 svi_load_line_vddc;
- u8 tdc_vddc_throttle_release_limit_perc;
- u8 tdc_mawt;
- u8 tdc_waterfall_ctl;
- u8 dte_ambient_temp_base;
- u32 display_cac;
- u32 bapm_temp_gradient;
- u16 bapmti_r[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS];
- u16 bapmti_rc[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS];
-};
-
-#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
-#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
-#define DPMTABLE_UPDATE_SCLK 0x00000004
-#define DPMTABLE_UPDATE_MCLK 0x00000008
-
-struct ci_power_info {
- struct ci_dpm_table dpm_table;
- struct ci_dpm_table golden_dpm_table;
- u32 voltage_control;
- u32 mvdd_control;
- u32 vddci_control;
- u32 active_auto_throttle_sources;
- struct ci_clock_registers clock_registers;
- u16 acpi_vddc;
- u16 acpi_vddci;
- enum amdgpu_pcie_gen force_pcie_gen;
- enum amdgpu_pcie_gen acpi_pcie_gen;
- struct ci_leakage_voltage vddc_leakage;
- struct ci_leakage_voltage vddci_leakage;
- u16 max_vddc_in_pp_table;
- u16 min_vddc_in_pp_table;
- u16 max_vddci_in_pp_table;
- u16 min_vddci_in_pp_table;
- u32 mclk_strobe_mode_threshold;
- u32 mclk_stutter_mode_threshold;
- u32 mclk_edc_enable_threshold;
- u32 mclk_edc_wr_enable_threshold;
- struct ci_vbios_boot_state vbios_boot_state;
- /* smc offsets */
- u32 sram_end;
- u32 dpm_table_start;
- u32 soft_regs_start;
- u32 mc_reg_table_start;
- u32 fan_table_start;
- u32 arb_table_start;
- /* smc tables */
- SMU7_Discrete_DpmTable smc_state_table;
- SMU7_Discrete_MCRegisters smc_mc_reg_table;
- SMU7_Discrete_PmFuses smc_powertune_table;
- /* other stuff */
- struct ci_mc_reg_table mc_reg_table;
- struct atom_voltage_table vddc_voltage_table;
- struct atom_voltage_table vddci_voltage_table;
- struct atom_voltage_table mvdd_voltage_table;
- struct ci_ulv_parm ulv;
- u32 power_containment_features;
- const struct ci_pt_defaults *powertune_defaults;
- u32 dte_tj_offset;
- bool vddc_phase_shed_control;
- struct ci_thermal_temperature_setting thermal_temp_setting;
- struct ci_dpm_level_enable_mask dpm_level_enable_mask;
- u32 need_update_smu7_dpm_table;
- u32 sclk_dpm_key_disabled;
- u32 mclk_dpm_key_disabled;
- u32 pcie_dpm_key_disabled;
- u32 thermal_sclk_dpm_enabled;
- struct ci_pcie_perf_range pcie_gen_performance;
- struct ci_pcie_perf_range pcie_lane_performance;
- struct ci_pcie_perf_range pcie_gen_powersaving;
- struct ci_pcie_perf_range pcie_lane_powersaving;
- u32 activity_target[SMU7_MAX_LEVELS_GRAPHICS];
- u32 mclk_activity_target;
- u32 low_sclk_interrupt_t;
- u32 last_mclk_dpm_enable_mask;
- u32 sys_pcie_mask;
- /* caps */
- bool caps_power_containment;
- bool caps_cac;
- bool caps_sq_ramping;
- bool caps_db_ramping;
- bool caps_td_ramping;
- bool caps_tcp_ramping;
- bool caps_fps;
- bool caps_sclk_ds;
- bool caps_sclk_ss_support;
- bool caps_mclk_ss_support;
- bool caps_uvd_dpm;
- bool caps_vce_dpm;
- bool caps_samu_dpm;
- bool caps_acp_dpm;
- bool caps_automatic_dc_transition;
- bool caps_sclk_throttle_low_notification;
- bool caps_dynamic_ac_timing;
- bool caps_od_fuzzy_fan_control_support;
- /* flags */
- bool thermal_protection;
- bool pcie_performance_request;
- bool dynamic_ss;
- bool dll_default_on;
- bool cac_enabled;
- bool uvd_enabled;
- bool battery_state;
- bool pspp_notify_required;
- bool enable_bapm_feature;
- bool enable_tdc_limit_feature;
- bool enable_pkg_pwr_tracking_feature;
- bool use_pcie_performance_levels;
- bool use_pcie_powersaving_levels;
- bool uvd_power_gated;
- /* driver states */
- struct amdgpu_ps current_rps;
- struct ci_ps current_ps;
- struct amdgpu_ps requested_rps;
- struct ci_ps requested_ps;
- /* fan control */
- bool fan_ctrl_is_in_default_mode;
- bool fan_is_controlled_by_smc;
- u32 t_min;
- u32 fan_ctrl_default_mode;
-};
-
-#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0
-#define CISLANDS_VOLTAGE_CONTROL_BY_GPIO 0x1
-#define CISLANDS_VOLTAGE_CONTROL_BY_SVID2 0x2
-
-#define CISLANDS_Q88_FORMAT_CONVERSION_UNIT 256
-
-#define CISLANDS_VRC_DFLT0 0x3FFFC000
-#define CISLANDS_VRC_DFLT1 0x000400
-#define CISLANDS_VRC_DFLT2 0xC00080
-#define CISLANDS_VRC_DFLT3 0xC00200
-#define CISLANDS_VRC_DFLT4 0xC01680
-#define CISLANDS_VRC_DFLT5 0xC00033
-#define CISLANDS_VRC_DFLT6 0xC00033
-#define CISLANDS_VRC_DFLT7 0x3FFFC000
-
-#define CISLANDS_CGULVPARAMETER_DFLT 0x00040035
-#define CISLAND_TARGETACTIVITY_DFLT 30
-#define CISLAND_MCLK_TARGETACTIVITY_DFLT 10
-
-#define PCIE_PERF_REQ_REMOVE_REGISTRY 0
-#define PCIE_PERF_REQ_FORCE_LOWPOWER 1
-#define PCIE_PERF_REQ_PECI_GEN1 2
-#define PCIE_PERF_REQ_PECI_GEN2 3
-#define PCIE_PERF_REQ_PECI_GEN3 4
-
-#define CISLANDS_SSTU_DFLT 0
-#define CISLANDS_SST_DFLT 0x00C8
-
-/* XXX are these ok? */
-#define CISLANDS_TEMP_RANGE_MIN (90 * 1000)
-#define CISLANDS_TEMP_RANGE_MAX (120 * 1000)
-
-int amdgpu_ci_copy_bytes_to_smc(struct amdgpu_device *adev,
- u32 smc_start_address,
- const u8 *src, u32 byte_count, u32 limit);
-void amdgpu_ci_start_smc(struct amdgpu_device *adev);
-void amdgpu_ci_reset_smc(struct amdgpu_device *adev);
-int amdgpu_ci_program_jump_on_start(struct amdgpu_device *adev);
-void amdgpu_ci_stop_smc_clock(struct amdgpu_device *adev);
-void amdgpu_ci_start_smc_clock(struct amdgpu_device *adev);
-bool amdgpu_ci_is_smc_running(struct amdgpu_device *adev);
-PPSMC_Result amdgpu_ci_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg);
-PPSMC_Result amdgpu_ci_wait_for_smc_inactive(struct amdgpu_device *adev);
-int amdgpu_ci_load_smc_ucode(struct amdgpu_device *adev, u32 limit);
-int amdgpu_ci_read_smc_sram_dword(struct amdgpu_device *adev,
- u32 smc_address, u32 *value, u32 limit);
-int amdgpu_ci_write_smc_sram_dword(struct amdgpu_device *adev,
- u32 smc_address, u32 value, u32 limit);
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_smc.c b/drivers/gpu/drm/amd/amdgpu/ci_smc.c
deleted file mode 100644
index b8ba51e045b5..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/ci_smc.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright 2011 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Alex Deucher
- */
-
-#include <linux/firmware.h>
-#include <drm/drmP.h>
-#include "amdgpu.h"
-#include "cikd.h"
-#include "ppsmc.h"
-#include "amdgpu_ucode.h"
-#include "ci_dpm.h"
-
-#include "smu/smu_7_0_1_d.h"
-#include "smu/smu_7_0_1_sh_mask.h"
-
-static int ci_set_smc_sram_address(struct amdgpu_device *adev,
- u32 smc_address, u32 limit)
-{
- if (smc_address & 3)
- return -EINVAL;
- if ((smc_address + 3) > limit)
- return -EINVAL;
-
- WREG32(mmSMC_IND_INDEX_0, smc_address);
- WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
-
- return 0;
-}
-
-int amdgpu_ci_copy_bytes_to_smc(struct amdgpu_device *adev,
- u32 smc_start_address,
- const u8 *src, u32 byte_count, u32 limit)
-{
- unsigned long flags;
- u32 data, original_data;
- u32 addr;
- u32 extra_shift;
- int ret = 0;
-
- if (smc_start_address & 3)
- return -EINVAL;
- if ((smc_start_address + byte_count) > limit)
- return -EINVAL;
-
- addr = smc_start_address;
-
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
- while (byte_count >= 4) {
- /* SMC address space is BE */
- data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
-
- ret = ci_set_smc_sram_address(adev, addr, limit);
- if (ret)
- goto done;
-
- WREG32(mmSMC_IND_DATA_0, data);
-
- src += 4;
- byte_count -= 4;
- addr += 4;
- }
-
- /* RMW for the final bytes */
- if (byte_count > 0) {
- data = 0;
-
- ret = ci_set_smc_sram_address(adev, addr, limit);
- if (ret)
- goto done;
-
- original_data = RREG32(mmSMC_IND_DATA_0);
-
- extra_shift = 8 * (4 - byte_count);
-
- while (byte_count > 0) {
- data = (data << 8) + *src++;
- byte_count--;
- }
-
- data <<= extra_shift;
-
- data |= (original_data & ~((~0UL) << extra_shift));
-
- ret = ci_set_smc_sram_address(adev, addr, limit);
- if (ret)
- goto done;
-
- WREG32(mmSMC_IND_DATA_0, data);
- }
-
-done:
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
- return ret;
-}
-
-void amdgpu_ci_start_smc(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-
- tmp &= ~SMC_SYSCON_RESET_CNTL__rst_reg_MASK;
- WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, tmp);
-}
-
-void amdgpu_ci_reset_smc(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-
- tmp |= SMC_SYSCON_RESET_CNTL__rst_reg_MASK;
- WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, tmp);
-}
-
-int amdgpu_ci_program_jump_on_start(struct amdgpu_device *adev)
-{
- static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
-
- return amdgpu_ci_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
-}
-
-void amdgpu_ci_stop_smc_clock(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-
- tmp |= SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK;
-
- WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, tmp);
-}
-
-void amdgpu_ci_start_smc_clock(struct amdgpu_device *adev)
-{
- u32 tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-
- tmp &= ~SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK;
-
- WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, tmp);
-}
-
-bool amdgpu_ci_is_smc_running(struct amdgpu_device *adev)
-{
- u32 clk = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
- u32 pc_c = RREG32_SMC(ixSMC_PC_C);
-
- if (!(clk & SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK) && (0x20100 <= pc_c))
- return true;
-
- return false;
-}
-
-PPSMC_Result amdgpu_ci_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
-{
- u32 tmp;
- int i;
-
- if (!amdgpu_ci_is_smc_running(adev))
- return PPSMC_Result_Failed;
-
- WREG32(mmSMC_MESSAGE_0, msg);
-
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = RREG32(mmSMC_RESP_0);
- if (tmp != 0)
- break;
- udelay(1);
- }
- tmp = RREG32(mmSMC_RESP_0);
-
- return (PPSMC_Result)tmp;
-}
-
-PPSMC_Result amdgpu_ci_wait_for_smc_inactive(struct amdgpu_device *adev)
-{
- u32 tmp;
- int i;
-
- if (!amdgpu_ci_is_smc_running(adev))
- return PPSMC_Result_OK;
-
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
- if ((tmp & SMC_SYSCON_CLOCK_CNTL_0__cken_MASK) == 0)
- break;
- udelay(1);
- }
-
- return PPSMC_Result_OK;
-}
-
-int amdgpu_ci_load_smc_ucode(struct amdgpu_device *adev, u32 limit)
-{
- const struct smc_firmware_header_v1_0 *hdr;
- unsigned long flags;
- u32 ucode_start_address;
- u32 ucode_size;
- const u8 *src;
- u32 data;
-
- if (!adev->pm.fw)
- return -EINVAL;
-
- hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
- amdgpu_ucode_print_smc_hdr(&hdr->header);
-
- adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
- ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
- ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
- src = (const u8 *)
- (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-
- if (ucode_size & 3)
- return -EINVAL;
-
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
- WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
- WREG32_P(mmSMC_IND_ACCESS_CNTL, SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK,
- ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
- while (ucode_size >= 4) {
- /* SMC address space is BE */
- data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
-
- WREG32(mmSMC_IND_DATA_0, data);
-
- src += 4;
- ucode_size -= 4;
- }
- WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
- return 0;
-}
-
-int amdgpu_ci_read_smc_sram_dword(struct amdgpu_device *adev,
- u32 smc_address, u32 *value, u32 limit)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
- ret = ci_set_smc_sram_address(adev, smc_address, limit);
- if (ret == 0)
- *value = RREG32(mmSMC_IND_DATA_0);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
- return ret;
-}
-
-int amdgpu_ci_write_smc_sram_dword(struct amdgpu_device *adev,
- u32 smc_address, u32 value, u32 limit)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
- ret = ci_set_smc_sram_address(adev, smc_address, limit);
- if (ret == 0)
- WREG32(mmSMC_IND_DATA_0, value);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
index 71c50d8900e3..07c1f239e9c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -1741,6 +1741,69 @@ static bool cik_need_full_reset(struct amdgpu_device *adev)
return true;
}
+static void cik_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
+ uint64_t *count1)
+{
+ uint32_t perfctr = 0;
+ uint64_t cnt0_of, cnt1_of;
+ int tmp;
+
+ /* This reports 0 on APUs, so return to avoid writing/reading registers
+ * that may or may not be different from their GPU counterparts
+ */
+ if (adev->flags & AMD_IS_APU)
+ return;
+
+ /* Set the 2 events that we wish to watch, defined above */
+ /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+
+ /* Write to enable desired perf counters */
+ WREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK, perfctr);
+ /* Zero out and enable the perf counters
+ * Write 0x5:
+ * Bit 0 = Start all counters(1)
+ * Bit 2 = Global counter reset enable(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000005);
+
+ msleep(1000);
+
+ /* Load the shadow and disable the perf counters
+ * Write 0x2:
+ * Bit 0 = Stop counters(0)
+ * Bit 1 = Load the shadow counters(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000002);
+
+ /* Read register values to get any >32bit overflow */
+ tmp = RREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK);
+ cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER);
+ cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER);
+
+ /* Get the values and add the overflow */
+ *count0 = RREG32_PCIE(ixPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32);
+ *count1 = RREG32_PCIE(ixPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32);
+}
+
+static bool cik_need_reset_on_init(struct amdgpu_device *adev)
+{
+ u32 clock_cntl, pc;
+
+ if (adev->flags & AMD_IS_APU)
+ return false;
+
+ /* check if the SMC is already running */
+ clock_cntl = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+ pc = RREG32_SMC(ixSMC_PC_C);
+ if ((0 == REG_GET_FIELD(clock_cntl, SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) &&
+ (0x20100 <= pc))
+ return true;
+
+ return false;
+}
+
static const struct amdgpu_asic_funcs cik_asic_funcs =
{
.read_disabled_bios = &cik_read_disabled_bios,
@@ -1756,6 +1819,8 @@ static const struct amdgpu_asic_funcs cik_asic_funcs =
.invalidate_hdp = &cik_invalidate_hdp,
.need_full_reset = &cik_need_full_reset,
.init_doorbell_index = &legacy_doorbell_index_init,
+ .get_pcie_usage = &cik_get_pcie_usage,
+ .need_reset_on_init = &cik_need_reset_on_init,
};
static int cik_common_early_init(void *handle)
@@ -2005,10 +2070,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
amdgpu_device_ip_block_add(adev, &gfx_v7_2_ip_block);
amdgpu_device_ip_block_add(adev, &cik_sdma_ip_block);
- if (amdgpu_dpm == -1)
- amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
- else
- amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
+ amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
@@ -2026,10 +2088,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
amdgpu_device_ip_block_add(adev, &gfx_v7_3_ip_block);
amdgpu_device_ip_block_add(adev, &cik_sdma_ip_block);
- if (amdgpu_dpm == -1)
- amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
- else
- amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
+ amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h
index 2a086610f74d..2fcc4b60153c 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h
@@ -24,7 +24,6 @@
#ifndef __CIK_DPM_H__
#define __CIK_DPM_H__
-extern const struct amdgpu_ip_block_version ci_smu_ip_block;
extern const struct amdgpu_ip_block_version kv_smu_ip_block;
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
index 8a8b4967a101..721c757156e8 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -103,9 +103,9 @@ static void cik_ih_disable_interrupts(struct amdgpu_device *adev)
*/
static int cik_ih_irq_init(struct amdgpu_device *adev)
{
+ struct amdgpu_ih_ring *ih = &adev->irq.ih;
int rb_bufsz;
u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
- u64 wptr_off;
/* disable irqs */
cik_ih_disable_interrupts(adev);
@@ -131,9 +131,8 @@ static int cik_ih_irq_init(struct amdgpu_device *adev)
ih_rb_cntl |= IH_RB_CNTL__WPTR_WRITEBACK_ENABLE_MASK;
/* set the writeback address whether it's enabled or not */
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
WREG32(mmIH_RB_CNTL, ih_rb_cntl);
@@ -183,11 +182,12 @@ static void cik_ih_irq_disable(struct amdgpu_device *adev)
* Used by cik_irq_process().
* Returns the value of the wptr.
*/
-static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
+static u32 cik_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
u32 wptr, tmp;
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) {
wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK;
@@ -196,13 +196,13 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
* this should allow us to catchup.
*/
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
- adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
+ ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(mmIH_RB_CNTL);
tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
WREG32(mmIH_RB_CNTL, tmp);
}
- return (wptr & adev->irq.ih.ptr_mask);
+ return (wptr & ih->ptr_mask);
}
/* CIK IV Ring
@@ -237,16 +237,17 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
* position and also advance the position.
*/
static void cik_ih_decode_iv(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih,
struct amdgpu_iv_entry *entry)
{
/* wptr/rptr are in bytes! */
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[4];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
entry->src_id = dw[0] & 0xff;
@@ -256,7 +257,7 @@ static void cik_ih_decode_iv(struct amdgpu_device *adev,
entry->pasid = (dw[2] >> 16) & 0xffff;
/* wptr/rptr are in bytes! */
- adev->irq.ih.rptr += 16;
+ ih->rptr += 16;
}
/**
@@ -266,9 +267,10 @@ static void cik_ih_decode_iv(struct amdgpu_device *adev,
*
* Set the IH ring buffer rptr.
*/
-static void cik_ih_set_rptr(struct amdgpu_device *adev)
+static void cik_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+ WREG32(mmIH_RB_RPTR, ih->rptr);
}
static int cik_ih_early_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index 45795191de1f..189599b694e8 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -220,7 +220,7 @@ static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 extra_bits = vmid & 0xf;
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
index 9d3ea298e116..61024b9c7a4b 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -103,9 +103,9 @@ static void cz_ih_disable_interrupts(struct amdgpu_device *adev)
*/
static int cz_ih_irq_init(struct amdgpu_device *adev)
{
- int rb_bufsz;
+ struct amdgpu_ih_ring *ih = &adev->irq.ih;
u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
- u64 wptr_off;
+ int rb_bufsz;
/* disable irqs */
cz_ih_disable_interrupts(adev);
@@ -133,9 +133,8 @@ static int cz_ih_irq_init(struct amdgpu_device *adev)
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
/* set the writeback address whether it's enabled or not */
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
WREG32(mmIH_RB_CNTL, ih_rb_cntl);
@@ -185,11 +184,12 @@ static void cz_ih_irq_disable(struct amdgpu_device *adev)
* Used by cz_irq_process(VI).
* Returns the value of the wptr.
*/
-static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
+static u32 cz_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
u32 wptr, tmp;
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
@@ -198,13 +198,13 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
* this should allow us to catchup.
*/
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
- adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
+ ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp);
}
- return (wptr & adev->irq.ih.ptr_mask);
+ return (wptr & ih->ptr_mask);
}
/**
@@ -216,16 +216,17 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
* position and also advance the position.
*/
static void cz_ih_decode_iv(struct amdgpu_device *adev,
- struct amdgpu_iv_entry *entry)
+ struct amdgpu_ih_ring *ih,
+ struct amdgpu_iv_entry *entry)
{
/* wptr/rptr are in bytes! */
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[4];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
entry->src_id = dw[0] & 0xff;
@@ -235,7 +236,7 @@ static void cz_ih_decode_iv(struct amdgpu_device *adev,
entry->pasid = (dw[2] >> 16) & 0xffff;
/* wptr/rptr are in bytes! */
- adev->irq.ih.rptr += 16;
+ ih->rptr += 16;
}
/**
@@ -245,9 +246,10 @@ static void cz_ih_decode_iv(struct amdgpu_device *adev,
*
* Set the IH ring buffer rptr.
*/
-static void cz_ih_set_rptr(struct amdgpu_device *adev)
+static void cz_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+ WREG32(mmIH_RB_RPTR, ih->rptr);
}
static int cz_ih_early_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
index fdace004544d..e4cc1d48eaab 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
@@ -167,19 +167,6 @@ static void dce_virtual_crtc_disable(struct drm_crtc *crtc)
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
- if (crtc->primary->fb) {
- int r;
- struct amdgpu_bo *abo;
-
- abo = gem_to_amdgpu_bo(crtc->primary->fb->obj[0]);
- r = amdgpu_bo_reserve(abo, true);
- if (unlikely(r))
- DRM_ERROR("failed to reserve abo before unpin\n");
- else {
- amdgpu_bo_unpin(abo);
- amdgpu_bo_unreserve(abo);
- }
- }
amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
amdgpu_crtc->encoder = NULL;
@@ -692,7 +679,9 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev,
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
drm_crtc_vblank_put(&amdgpu_crtc->base);
- schedule_work(&works->unpin_work);
+ amdgpu_bo_unref(&works->old_abo);
+ kfree(works->shared);
+ kfree(works);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 1dc3013ea1d5..305276c7e4bf 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1842,13 +1842,13 @@ static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
- if (ctx_switch) {
+ if (flags & AMDGPU_HAVE_CTX_SWITCH) {
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 3a9fb6018c16..a59e0fdf5a97 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -2228,13 +2228,13 @@ static void gfx_v7_0_ring_emit_fence_compute(struct amdgpu_ring *ring,
static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
- if (ctx_switch) {
+ if (flags & AMDGPU_HAVE_CTX_SWITCH) {
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
@@ -2259,11 +2259,27 @@ static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
+ /* Currently, there is a high possibility to get wave ID mismatch
+ * between ME and GDS, leading to a hw deadlock, because ME generates
+ * different wave IDs than the GDS expects. This situation happens
+ * randomly when at least 5 compute pipes use GDS ordered append.
+ * The wave IDs generated by ME are also wrong after suspend/resume.
+ * Those are probably bugs somewhere else in the kernel driver.
+ *
+ * Writing GDS_COMPUTE_MAX_WAVE_ID resets wave ID counters in ME and
+ * GDS to 0 for this ring (me/pipe).
+ */
+ if (ib->flags & AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID) {
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ amdgpu_ring_write(ring, mmGDS_COMPUTE_MAX_WAVE_ID - PACKET3_SET_CONFIG_REG_START);
+ amdgpu_ring_write(ring, ring->adev->gds.gds_compute_max_wave_id);
+ }
+
amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
amdgpu_ring_write(ring,
#ifdef __BIG_ENDIAN
@@ -5000,7 +5016,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
7 + /* gfx_v7_0_ring_emit_pipeline_sync */
CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v7_0_ring_emit_vm_flush */
7 + 7 + 7, /* gfx_v7_0_ring_emit_fence_compute x3 for user fence, vm fence */
- .emit_ib_size = 4, /* gfx_v7_0_ring_emit_ib_compute */
+ .emit_ib_size = 7, /* gfx_v7_0_ring_emit_ib_compute */
.emit_ib = gfx_v7_0_ring_emit_ib_compute,
.emit_fence = gfx_v7_0_ring_emit_fence_compute,
.emit_pipeline_sync = gfx_v7_0_ring_emit_pipeline_sync,
@@ -5057,6 +5073,7 @@ static void gfx_v7_0_set_gds_init(struct amdgpu_device *adev)
adev->gds.mem.total_size = RREG32(mmGDS_VMID0_SIZE);
adev->gds.gws.total_size = 64;
adev->gds.oa.total_size = 16;
+ adev->gds.gds_compute_max_wave_id = RREG32(mmGDS_COMPUTE_MAX_WAVE_ID);
if (adev->gds.mem.total_size == 64 * 1024) {
adev->gds.mem.gfx_partition_size = 4096;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 381f593b0cda..b8e50a34bdb3 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -4233,7 +4233,6 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev)
u32 tmp;
u32 rb_bufsz;
u64 rb_addr, rptr_addr, wptr_gpu_addr;
- int r;
/* Set the write pointer delay */
WREG32(mmCP_RB_WPTR_DELAY, 0);
@@ -4278,9 +4277,8 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev)
amdgpu_ring_clear_ring(ring);
gfx_v8_0_cp_gfx_start(adev);
ring->sched.ready = true;
- r = amdgpu_ring_test_helper(ring);
- return r;
+ return 0;
}
static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
@@ -4369,10 +4367,9 @@ static int gfx_v8_0_kiq_kcq_enable(struct amdgpu_device *adev)
amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
}
- r = amdgpu_ring_test_helper(kiq_ring);
- if (r)
- DRM_ERROR("KCQ enable failed\n");
- return r;
+ amdgpu_ring_commit(kiq_ring);
+
+ return 0;
}
static int gfx_v8_0_deactivate_hqd(struct amdgpu_device *adev, u32 req)
@@ -4709,16 +4706,32 @@ static int gfx_v8_0_kcq_resume(struct amdgpu_device *adev)
if (r)
goto done;
- /* Test KCQs - reversing the order of rings seems to fix ring test failure
- * after GPU reset
- */
- for (i = adev->gfx.num_compute_rings - 1; i >= 0; i--) {
+done:
+ return r;
+}
+
+static int gfx_v8_0_cp_test_all_rings(struct amdgpu_device *adev)
+{
+ int r, i;
+ struct amdgpu_ring *ring;
+
+ /* collect all the ring_tests here, gfx, kiq, compute */
+ ring = &adev->gfx.gfx_ring[0];
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
+ return r;
+
+ ring = &adev->gfx.kiq.ring;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
+ return r;
+
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
- r = amdgpu_ring_test_helper(ring);
+ amdgpu_ring_test_helper(ring);
}
-done:
- return r;
+ return 0;
}
static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
@@ -4739,6 +4752,11 @@ static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
r = gfx_v8_0_kcq_resume(adev);
if (r)
return r;
+
+ r = gfx_v8_0_cp_test_all_rings(adev);
+ if (r)
+ return r;
+
gfx_v8_0_enable_gui_idle_interrupt(adev, true);
return 0;
@@ -5086,6 +5104,8 @@ static int gfx_v8_0_post_soft_reset(void *handle)
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
gfx_v8_0_cp_gfx_resume(adev);
+ gfx_v8_0_cp_test_all_rings(adev);
+
adev->gfx.rlc.funcs->start(adev);
return 0;
@@ -6027,7 +6047,7 @@ static void gfx_v8_0_ring_emit_vgt_flush(struct amdgpu_ring *ring)
static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
@@ -6059,11 +6079,27 @@ static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
+ /* Currently, there is a high possibility to get wave ID mismatch
+ * between ME and GDS, leading to a hw deadlock, because ME generates
+ * different wave IDs than the GDS expects. This situation happens
+ * randomly when at least 5 compute pipes use GDS ordered append.
+ * The wave IDs generated by ME are also wrong after suspend/resume.
+ * Those are probably bugs somewhere else in the kernel driver.
+ *
+ * Writing GDS_COMPUTE_MAX_WAVE_ID resets wave ID counters in ME and
+ * GDS to 0 for this ring (me/pipe).
+ */
+ if (ib->flags & AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID) {
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ amdgpu_ring_write(ring, mmGDS_COMPUTE_MAX_WAVE_ID - PACKET3_SET_CONFIG_REG_START);
+ amdgpu_ring_write(ring, ring->adev->gds.gds_compute_max_wave_id);
+ }
+
amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
amdgpu_ring_write(ring,
#ifdef __BIG_ENDIAN
@@ -6870,7 +6906,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
7 + /* gfx_v8_0_ring_emit_pipeline_sync */
VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v8_0_ring_emit_vm_flush */
7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_compute x3 for user fence, vm fence */
- .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */
+ .emit_ib_size = 7, /* gfx_v8_0_ring_emit_ib_compute */
.emit_ib = gfx_v8_0_ring_emit_ib_compute,
.emit_fence = gfx_v8_0_ring_emit_fence_compute,
.emit_pipeline_sync = gfx_v8_0_ring_emit_pipeline_sync,
@@ -6900,7 +6936,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = {
7 + /* gfx_v8_0_ring_emit_pipeline_sync */
17 + /* gfx_v8_0_ring_emit_vm_flush */
7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_kiq x3 for user fence, vm fence */
- .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */
+ .emit_ib_size = 7, /* gfx_v8_0_ring_emit_ib_compute */
.emit_fence = gfx_v8_0_ring_emit_fence_kiq,
.test_ring = gfx_v8_0_ring_test_ring,
.insert_nop = amdgpu_ring_insert_nop,
@@ -6976,6 +7012,7 @@ static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev)
adev->gds.mem.total_size = RREG32(mmGDS_VMID0_SIZE);
adev->gds.gws.total_size = 64;
adev->gds.oa.total_size = 16;
+ adev->gds.gds_compute_max_wave_id = RREG32(mmGDS_COMPUTE_MAX_WAVE_ID);
if (adev->gds.mem.total_size == 64 * 1024) {
adev->gds.mem.gfx_partition_size = 4096;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 7556716038d3..5533f6e4f4a4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -113,7 +113,10 @@ static const struct soc15_reg_golden golden_settings_gc_9_0[] =
SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CHAN_STEER_HI, 0xffffffff, 0x4a2c0e68),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CHAN_STEER_LO, 0xffffffff, 0xb5d3f197),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_CACHE_INVALIDATION, 0x3fff3af3, 0x19200000),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_GS_MAX_WAVE_ID, 0x00000fff, 0x000003ff)
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_GS_MAX_WAVE_ID, 0x00000fff, 0x000003ff),
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC1_F32_INT_DIS, 0x00000000, 0x00000800),
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC2_F32_INT_DIS, 0x00000000, 0x00000800),
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_DEBUG, 0x00000000, 0x00008000)
};
static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] =
@@ -135,10 +138,7 @@ static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] =
SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_UTCL1_CNTL2, 0x00030000, 0x00020000),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL_1, 0x0000000f, 0x01000107),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmTD_CNTL, 0x00001800, 0x00000800),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmWD_UTCL1_CNTL, 0x08000000, 0x08000080),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC1_F32_INT_DIS, 0x00000000, 0x00000800),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC2_F32_INT_DIS, 0x00000000, 0x00000800),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_DEBUG, 0x00000000, 0x00008000)
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmWD_UTCL1_CNTL, 0x08000000, 0x08000080)
};
static const struct soc15_reg_golden golden_settings_gc_9_0_vg20[] =
@@ -3587,6 +3587,8 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
{
uint32_t data, def;
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
+
/* It is disabled by HW by default */
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
/* 1 - RLC_CGTT_MGCG_OVERRIDE */
@@ -3651,6 +3653,8 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
}
}
+
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev,
@@ -3968,7 +3972,7 @@ static void gfx_v9_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
@@ -4001,11 +4005,27 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
+ /* Currently, there is a high possibility to get wave ID mismatch
+ * between ME and GDS, leading to a hw deadlock, because ME generates
+ * different wave IDs than the GDS expects. This situation happens
+ * randomly when at least 5 compute pipes use GDS ordered append.
+ * The wave IDs generated by ME are also wrong after suspend/resume.
+ * Those are probably bugs somewhere else in the kernel driver.
+ *
+ * Writing GDS_COMPUTE_MAX_WAVE_ID resets wave ID counters in ME and
+ * GDS to 0 for this ring (me/pipe).
+ */
+ if (ib->flags & AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID) {
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ amdgpu_ring_write(ring, mmGDS_COMPUTE_MAX_WAVE_ID);
+ amdgpu_ring_write(ring, ring->adev->gds.gds_compute_max_wave_id);
+ }
+
amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
amdgpu_ring_write(ring,
@@ -4725,7 +4745,7 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = {
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 +
2 + /* gfx_v9_0_ring_emit_vm_flush */
8 + 8 + 8, /* gfx_v9_0_ring_emit_fence x3 for user fence, vm fence */
- .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */
+ .emit_ib_size = 7, /* gfx_v9_0_ring_emit_ib_compute */
.emit_ib = gfx_v9_0_ring_emit_ib_compute,
.emit_fence = gfx_v9_0_ring_emit_fence,
.emit_pipeline_sync = gfx_v9_0_ring_emit_pipeline_sync,
@@ -4760,7 +4780,7 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = {
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 +
2 + /* gfx_v9_0_ring_emit_vm_flush */
8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */
- .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */
+ .emit_ib_size = 7, /* gfx_v9_0_ring_emit_ib_compute */
.emit_fence = gfx_v9_0_ring_emit_fence_kiq,
.test_ring = gfx_v9_0_ring_test_ring,
.insert_nop = amdgpu_ring_insert_nop,
@@ -4842,6 +4862,26 @@ static void gfx_v9_0_set_gds_init(struct amdgpu_device *adev)
break;
}
+ switch (adev->asic_type) {
+ case CHIP_VEGA10:
+ case CHIP_VEGA20:
+ adev->gds.gds_compute_max_wave_id = 0x7ff;
+ break;
+ case CHIP_VEGA12:
+ adev->gds.gds_compute_max_wave_id = 0x27f;
+ break;
+ case CHIP_RAVEN:
+ if (adev->rev_id >= 0x8)
+ adev->gds.gds_compute_max_wave_id = 0x77; /* raven2 */
+ else
+ adev->gds.gds_compute_max_wave_id = 0x15f; /* raven1 */
+ break;
+ default:
+ /* this really depends on the chip */
+ adev->gds.gds_compute_max_wave_id = 0x7ff;
+ break;
+ }
+
adev->gds.gws.total_size = 64;
adev->gds.oa.total_size = 16;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 1ad7e6b8ed1d..34440672f938 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -1471,8 +1471,9 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev,
gmc_v8_0_set_fault_enable_default(adev, false);
if (printk_ratelimit()) {
- struct amdgpu_task_info task_info = { 0 };
+ struct amdgpu_task_info task_info;
+ memset(&task_info, 0, sizeof(struct amdgpu_task_info));
amdgpu_vm_get_task_info(adev, entry->pasid, &task_info);
dev_err(adev->dev, "GPU fault detected: %d 0x%08x for process %s pid %d thread %s pid %d\n",
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index bacdaef77b6c..600259b4e291 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -305,6 +305,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
struct amdgpu_vmhub *hub = &adev->vmhub[entry->vmid_src];
+ bool retry_fault = !!(entry->src_data[1] & 0x80);
uint32_t status = 0;
u64 addr;
@@ -320,13 +321,16 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
}
if (printk_ratelimit()) {
- struct amdgpu_task_info task_info = { 0 };
+ struct amdgpu_task_info task_info;
+ memset(&task_info, 0, sizeof(struct amdgpu_task_info));
amdgpu_vm_get_task_info(adev, entry->pasid, &task_info);
dev_err(adev->dev,
- "[%s] VMC page fault (src_id:%u ring:%u vmid:%u pasid:%u, for process %s pid %d thread %s pid %d)\n",
+ "[%s] %s page fault (src_id:%u ring:%u vmid:%u "
+ "pasid:%u, for process %s pid %d thread %s pid %d)\n",
entry->vmid_src ? "mmhub" : "gfxhub",
+ retry_fault ? "retry" : "no-retry",
entry->src_id, entry->ring_id, entry->vmid,
entry->pasid, task_info.process_name, task_info.tgid,
task_info.task_name, task_info.pid);
@@ -961,7 +965,11 @@ static int gmc_v9_0_sw_init(void *handle)
* vm size is 256TB (48bit), maximum size of Vega10,
* block size 512 (9bit)
*/
- amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
+ /* sriov restrict max_pfn below AMDGPU_GMC_HOLE */
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 47);
+ else
+ amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
break;
default:
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
index a3984d10b604..b1626e1d2f5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -103,9 +103,9 @@ static void iceland_ih_disable_interrupts(struct amdgpu_device *adev)
*/
static int iceland_ih_irq_init(struct amdgpu_device *adev)
{
+ struct amdgpu_ih_ring *ih = &adev->irq.ih;
int rb_bufsz;
u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
- u64 wptr_off;
/* disable irqs */
iceland_ih_disable_interrupts(adev);
@@ -133,9 +133,8 @@ static int iceland_ih_irq_init(struct amdgpu_device *adev)
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
/* set the writeback address whether it's enabled or not */
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
WREG32(mmIH_RB_CNTL, ih_rb_cntl);
@@ -185,11 +184,12 @@ static void iceland_ih_irq_disable(struct amdgpu_device *adev)
* Used by cz_irq_process(VI).
* Returns the value of the wptr.
*/
-static u32 iceland_ih_get_wptr(struct amdgpu_device *adev)
+static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
u32 wptr, tmp;
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
@@ -198,13 +198,13 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev)
* this should allow us to catchup.
*/
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
- adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
+ ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp);
}
- return (wptr & adev->irq.ih.ptr_mask);
+ return (wptr & ih->ptr_mask);
}
/**
@@ -216,16 +216,17 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev)
* position and also advance the position.
*/
static void iceland_ih_decode_iv(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih,
struct amdgpu_iv_entry *entry)
{
/* wptr/rptr are in bytes! */
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[4];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
entry->src_id = dw[0] & 0xff;
@@ -235,7 +236,7 @@ static void iceland_ih_decode_iv(struct amdgpu_device *adev,
entry->pasid = (dw[2] >> 16) & 0xffff;
/* wptr/rptr are in bytes! */
- adev->irq.ih.rptr += 16;
+ ih->rptr += 16;
}
/**
@@ -245,9 +246,10 @@ static void iceland_ih_decode_iv(struct amdgpu_device *adev,
*
* Set the IH ring buffer rptr.
*/
-static void iceland_ih_set_rptr(struct amdgpu_device *adev)
+static void iceland_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+ WREG32(mmIH_RB_RPTR, ih->rptr);
}
static int iceland_ih_early_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
index 8cbb4655896a..b11a1c17a7f2 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
@@ -174,7 +174,7 @@ static int xgpu_ai_send_access_requests(struct amdgpu_device *adev,
return r;
}
/* Retrieve checksum from mailbox2 */
- if (req == IDH_REQ_GPU_INIT_ACCESS) {
+ if (req == IDH_REQ_GPU_INIT_ACCESS || req == IDH_REQ_GPU_RESET_ACCESS) {
adev->virt.fw_reserve.checksum_key =
RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0,
mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW2));
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c
index accdedd63c98..cc967dbfd631 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c
@@ -27,13 +27,9 @@
#include "nbio/nbio_6_1_default.h"
#include "nbio/nbio_6_1_offset.h"
#include "nbio/nbio_6_1_sh_mask.h"
+#include "nbio/nbio_6_1_smn.h"
#include "vega10_enum.h"
-#define smnCPM_CONTROL 0x11180460
-#define smnPCIE_CNTL2 0x11180070
-#define smnPCIE_CONFIG_CNTL 0x11180044
-#define smnPCIE_CI_CNTL 0x11180080
-
static u32 nbio_v6_1_get_rev_id(struct amdgpu_device *adev)
{
u32 tmp = RREG32_SOC15(NBIO, 0, mmRCC_DEV0_EPF0_STRAP0);
@@ -72,7 +68,7 @@ static u32 nbio_v6_1_get_memsize(struct amdgpu_device *adev)
}
static void nbio_v6_1_sdma_doorbell_range(struct amdgpu_device *adev, int instance,
- bool use_doorbell, int doorbell_index)
+ bool use_doorbell, int doorbell_index, int doorbell_size)
{
u32 reg = instance == 0 ? SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA0_DOORBELL_RANGE) :
SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA1_DOORBELL_RANGE);
@@ -81,7 +77,7 @@ static void nbio_v6_1_sdma_doorbell_range(struct amdgpu_device *adev, int instan
if (use_doorbell) {
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, OFFSET, doorbell_index);
- doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 2);
+ doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, doorbell_size);
} else
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c
index df34dc79d444..1cdb98ad2db3 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c
@@ -27,13 +27,11 @@
#include "nbio/nbio_7_0_default.h"
#include "nbio/nbio_7_0_offset.h"
#include "nbio/nbio_7_0_sh_mask.h"
+#include "nbio/nbio_7_0_smn.h"
#include "vega10_enum.h"
#define smnNBIF_MGCG_CTRL_LCLK 0x1013a05c
-#define smnCPM_CONTROL 0x11180460
-#define smnPCIE_CNTL2 0x11180070
-
static u32 nbio_v7_0_get_rev_id(struct amdgpu_device *adev)
{
u32 tmp = RREG32_SOC15(NBIO, 0, mmRCC_DEV0_EPF0_STRAP0);
@@ -69,7 +67,7 @@ static u32 nbio_v7_0_get_memsize(struct amdgpu_device *adev)
}
static void nbio_v7_0_sdma_doorbell_range(struct amdgpu_device *adev, int instance,
- bool use_doorbell, int doorbell_index)
+ bool use_doorbell, int doorbell_index, int doorbell_size)
{
u32 reg = instance == 0 ? SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA0_DOORBELL_RANGE) :
SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA1_DOORBELL_RANGE);
@@ -78,7 +76,7 @@ static void nbio_v7_0_sdma_doorbell_range(struct amdgpu_device *adev, int instan
if (use_doorbell) {
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, OFFSET, doorbell_index);
- doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 2);
+ doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, doorbell_size);
} else
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c
index 4cd31a276dcd..221f26e50322 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c
@@ -26,13 +26,10 @@
#include "nbio/nbio_7_4_offset.h"
#include "nbio/nbio_7_4_sh_mask.h"
+#include "nbio/nbio_7_4_0_smn.h"
#define smnNBIF_MGCG_CTRL_LCLK 0x1013a21c
-#define smnCPM_CONTROL 0x11180460
-#define smnPCIE_CNTL2 0x11180070
-#define smnPCIE_CI_CNTL 0x11180080
-
static u32 nbio_v7_4_get_rev_id(struct amdgpu_device *adev)
{
u32 tmp = RREG32_SOC15(NBIO, 0, mmRCC_DEV0_EPF0_STRAP0);
@@ -68,7 +65,7 @@ static u32 nbio_v7_4_get_memsize(struct amdgpu_device *adev)
}
static void nbio_v7_4_sdma_doorbell_range(struct amdgpu_device *adev, int instance,
- bool use_doorbell, int doorbell_index)
+ bool use_doorbell, int doorbell_index, int doorbell_size)
{
u32 reg = instance == 0 ? SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA0_DOORBELL_RANGE) :
SOC15_REG_OFFSET(NBIO, 0, mmBIF_SDMA1_DOORBELL_RANGE);
@@ -77,7 +74,7 @@ static void nbio_v7_4_sdma_doorbell_range(struct amdgpu_device *adev, int instan
if (use_doorbell) {
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, OFFSET, doorbell_index);
- doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 2);
+ doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, doorbell_size);
} else
doorbell_range = REG_SET_FIELD(doorbell_range, BIF_SDMA0_DOORBELL_RANGE, SIZE, 0);
@@ -93,7 +90,20 @@ static void nbio_v7_4_enable_doorbell_aperture(struct amdgpu_device *adev,
static void nbio_v7_4_enable_doorbell_selfring_aperture(struct amdgpu_device *adev,
bool enable)
{
+ u32 tmp = 0;
+
+ if (enable) {
+ tmp = REG_SET_FIELD(tmp, DOORBELL_SELFRING_GPA_APER_CNTL, DOORBELL_SELFRING_GPA_APER_EN, 1) |
+ REG_SET_FIELD(tmp, DOORBELL_SELFRING_GPA_APER_CNTL, DOORBELL_SELFRING_GPA_APER_MODE, 1) |
+ REG_SET_FIELD(tmp, DOORBELL_SELFRING_GPA_APER_CNTL, DOORBELL_SELFRING_GPA_APER_SIZE, 0);
+
+ WREG32_SOC15(NBIO, 0, mmDOORBELL_SELFRING_GPA_APER_BASE_LOW,
+ lower_32_bits(adev->doorbell.base));
+ WREG32_SOC15(NBIO, 0, mmDOORBELL_SELFRING_GPA_APER_BASE_HIGH,
+ upper_32_bits(adev->doorbell.base));
+ }
+ WREG32_SOC15(NBIO, 0, mmDOORBELL_SELFRING_GPA_APER_CNTL, tmp);
}
static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
index 0de00fbe9233..f3a7d207af07 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
+++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
@@ -191,7 +191,7 @@ enum psp_gfx_fw_type
GFX_FW_TYPE_MMSCH = 19,
GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM = 20,
GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM = 21,
- GFX_FW_TYPE_RLC_RESTORE_LIST_CNTL = 22,
+ GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL = 22,
GFX_FW_TYPE_UVD1 = 23,
GFX_FW_TYPE_MAX = 24
};
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
index d78b4306a36f..77c2bc344dfc 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
@@ -38,75 +38,6 @@ MODULE_FIRMWARE("amdgpu/raven_asd.bin");
MODULE_FIRMWARE("amdgpu/picasso_asd.bin");
MODULE_FIRMWARE("amdgpu/raven2_asd.bin");
-static int
-psp_v10_0_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type)
-{
- switch(ucode->ucode_id) {
- case AMDGPU_UCODE_ID_SDMA0:
- *type = GFX_FW_TYPE_SDMA0;
- break;
- case AMDGPU_UCODE_ID_SDMA1:
- *type = GFX_FW_TYPE_SDMA1;
- break;
- case AMDGPU_UCODE_ID_CP_CE:
- *type = GFX_FW_TYPE_CP_CE;
- break;
- case AMDGPU_UCODE_ID_CP_PFP:
- *type = GFX_FW_TYPE_CP_PFP;
- break;
- case AMDGPU_UCODE_ID_CP_ME:
- *type = GFX_FW_TYPE_CP_ME;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME1;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME2;
- break;
- case AMDGPU_UCODE_ID_RLC_G:
- *type = GFX_FW_TYPE_RLC_G;
- break;
- case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL:
- *type = GFX_FW_TYPE_RLC_RESTORE_LIST_CNTL;
- break;
- case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM:
- *type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM;
- break;
- case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM:
- *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM;
- break;
- case AMDGPU_UCODE_ID_SMC:
- *type = GFX_FW_TYPE_SMU;
- break;
- case AMDGPU_UCODE_ID_UVD:
- *type = GFX_FW_TYPE_UVD;
- break;
- case AMDGPU_UCODE_ID_VCE:
- *type = GFX_FW_TYPE_VCE;
- break;
- case AMDGPU_UCODE_ID_VCN:
- *type = GFX_FW_TYPE_VCN;
- break;
- case AMDGPU_UCODE_ID_DMCU_ERAM:
- *type = GFX_FW_TYPE_DMCU_ERAM;
- break;
- case AMDGPU_UCODE_ID_DMCU_INTV:
- *type = GFX_FW_TYPE_DMCU_ISR;
- break;
- case AMDGPU_UCODE_ID_MAXIMUM:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
static int psp_v10_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -158,26 +89,6 @@ out:
return err;
}
-static int psp_v10_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode,
- struct psp_gfx_cmd_resp *cmd)
-{
- int ret;
- uint64_t fw_mem_mc_addr = ucode->mc_addr;
-
- memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
-
- cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size;
-
- ret = psp_v10_0_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type);
- if (ret)
- DRM_ERROR("Unknown firmware type\n");
-
- return ret;
-}
-
static int psp_v10_0_ring_init(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -454,7 +365,6 @@ static int psp_v10_0_mode1_reset(struct psp_context *psp)
static const struct psp_funcs psp_v10_0_funcs = {
.init_microcode = psp_v10_0_init_microcode,
- .prep_cmd_buf = psp_v10_0_prep_cmd_buf,
.ring_init = psp_v10_0_ring_init,
.ring_create = psp_v10_0_ring_create,
.ring_stop = psp_v10_0_ring_stop,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index 0c6e7f9b143f..860b70d80d3c 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -40,60 +40,6 @@ MODULE_FIRMWARE("amdgpu/vega20_ta.bin");
/* address block */
#define smnMP1_FIRMWARE_FLAGS 0x3010024
-static int
-psp_v11_0_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type)
-{
- switch (ucode->ucode_id) {
- case AMDGPU_UCODE_ID_SDMA0:
- *type = GFX_FW_TYPE_SDMA0;
- break;
- case AMDGPU_UCODE_ID_SDMA1:
- *type = GFX_FW_TYPE_SDMA1;
- break;
- case AMDGPU_UCODE_ID_CP_CE:
- *type = GFX_FW_TYPE_CP_CE;
- break;
- case AMDGPU_UCODE_ID_CP_PFP:
- *type = GFX_FW_TYPE_CP_PFP;
- break;
- case AMDGPU_UCODE_ID_CP_ME:
- *type = GFX_FW_TYPE_CP_ME;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME1;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME2;
- break;
- case AMDGPU_UCODE_ID_RLC_G:
- *type = GFX_FW_TYPE_RLC_G;
- break;
- case AMDGPU_UCODE_ID_SMC:
- *type = GFX_FW_TYPE_SMU;
- break;
- case AMDGPU_UCODE_ID_UVD:
- *type = GFX_FW_TYPE_UVD;
- break;
- case AMDGPU_UCODE_ID_VCE:
- *type = GFX_FW_TYPE_VCE;
- break;
- case AMDGPU_UCODE_ID_UVD1:
- *type = GFX_FW_TYPE_UVD1;
- break;
- case AMDGPU_UCODE_ID_MAXIMUM:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
static int psp_v11_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -152,18 +98,22 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err)
- goto out2;
-
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out2;
-
- ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
- adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version);
- adev->psp.ta_xgmi_ucode_size = le32_to_cpu(ta_hdr->ta_xgmi_size_bytes);
- adev->psp.ta_xgmi_start_addr = (uint8_t *)ta_hdr +
- le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+ if (err) {
+ release_firmware(adev->psp.ta_fw);
+ adev->psp.ta_fw = NULL;
+ dev_info(adev->dev,
+ "psp v11.0: Failed to load firmware \"%s\"\n", fw_name);
+ } else {
+ err = amdgpu_ucode_validate(adev->psp.ta_fw);
+ if (err)
+ goto out2;
+
+ ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
+ adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version);
+ adev->psp.ta_xgmi_ucode_size = le32_to_cpu(ta_hdr->ta_xgmi_size_bytes);
+ adev->psp.ta_xgmi_start_addr = (uint8_t *)ta_hdr +
+ le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+ }
return 0;
@@ -267,26 +217,6 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v11_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode,
- struct psp_gfx_cmd_resp *cmd)
-{
- int ret;
- uint64_t fw_mem_mc_addr = ucode->mc_addr;
-
- memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
-
- cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size;
-
- ret = psp_v11_0_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type);
- if (ret)
- DRM_ERROR("Unknown firmware type\n");
-
- return ret;
-}
-
static int psp_v11_0_ring_init(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -753,7 +683,6 @@ static const struct psp_funcs psp_v11_0_funcs = {
.init_microcode = psp_v11_0_init_microcode,
.bootloader_load_sysdrv = psp_v11_0_bootloader_load_sysdrv,
.bootloader_load_sos = psp_v11_0_bootloader_load_sos,
- .prep_cmd_buf = psp_v11_0_prep_cmd_buf,
.ring_init = psp_v11_0_ring_init,
.ring_create = psp_v11_0_ring_create,
.ring_stop = psp_v11_0_ring_stop,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
index 79694ff16969..c63de945c021 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
@@ -47,57 +47,6 @@ MODULE_FIRMWARE("amdgpu/vega12_asd.bin");
static uint32_t sos_old_versions[] = {1517616, 1510592, 1448594, 1446554};
-static int
-psp_v3_1_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type)
-{
- switch(ucode->ucode_id) {
- case AMDGPU_UCODE_ID_SDMA0:
- *type = GFX_FW_TYPE_SDMA0;
- break;
- case AMDGPU_UCODE_ID_SDMA1:
- *type = GFX_FW_TYPE_SDMA1;
- break;
- case AMDGPU_UCODE_ID_CP_CE:
- *type = GFX_FW_TYPE_CP_CE;
- break;
- case AMDGPU_UCODE_ID_CP_PFP:
- *type = GFX_FW_TYPE_CP_PFP;
- break;
- case AMDGPU_UCODE_ID_CP_ME:
- *type = GFX_FW_TYPE_CP_ME;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME1;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2:
- *type = GFX_FW_TYPE_CP_MEC;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2_JT:
- *type = GFX_FW_TYPE_CP_MEC_ME2;
- break;
- case AMDGPU_UCODE_ID_RLC_G:
- *type = GFX_FW_TYPE_RLC_G;
- break;
- case AMDGPU_UCODE_ID_SMC:
- *type = GFX_FW_TYPE_SMU;
- break;
- case AMDGPU_UCODE_ID_UVD:
- *type = GFX_FW_TYPE_UVD;
- break;
- case AMDGPU_UCODE_ID_VCE:
- *type = GFX_FW_TYPE_VCE;
- break;
- case AMDGPU_UCODE_ID_MAXIMUM:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
static int psp_v3_1_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -277,26 +226,6 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
return ret;
}
-static int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode,
- struct psp_gfx_cmd_resp *cmd)
-{
- int ret;
- uint64_t fw_mem_mc_addr = ucode->mc_addr;
-
- memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
-
- cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr);
- cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size;
-
- ret = psp_v3_1_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type);
- if (ret)
- DRM_ERROR("Unknown firmware type\n");
-
- return ret;
-}
-
static int psp_v3_1_ring_init(struct psp_context *psp,
enum psp_ring_type ring_type)
{
@@ -615,7 +544,6 @@ static const struct psp_funcs psp_v3_1_funcs = {
.init_microcode = psp_v3_1_init_microcode,
.bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv,
.bootloader_load_sos = psp_v3_1_bootloader_load_sos,
- .prep_cmd_buf = psp_v3_1_prep_cmd_buf,
.ring_init = psp_v3_1_ring_init,
.ring_create = psp_v3_1_ring_create,
.ring_stop = psp_v3_1_ring_stop,
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index 9f3cb2aec7c2..cca3552b36ed 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -247,7 +247,7 @@ static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
static void sdma_v2_4_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 1bccc5fe2d9d..0ce8331baeb2 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -421,7 +421,7 @@ static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
static void sdma_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -1145,8 +1145,7 @@ static int sdma_v3_0_sw_init(void *handle)
ring->ring_obj = NULL;
if (!amdgpu_sriov_vf(adev)) {
ring->use_doorbell = true;
- ring->doorbell_index = (i == 0) ?
- adev->doorbell_index.sdma_engine0 : adev->doorbell_index.sdma_engine1;
+ ring->doorbell_index = adev->doorbell_index.sdma_engine[i];
} else {
ring->use_pollmem = true;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index fd0bfe140ee0..127b85983e8f 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -78,7 +78,6 @@ static const struct soc15_reg_golden golden_settings_sdma_4[] = {
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0x0000fff0, 0x00403000),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x00000000),
- SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831f07),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CLK_CTRL, 0xffffffff, 0x3f000100),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GFX_IB_CNTL, 0x800f0100, 0x00000100),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GFX_RB_WPTR_POLL_CNTL, 0x0000fff0, 0x00403000),
@@ -96,6 +95,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4[] = {
static const struct soc15_reg_golden golden_settings_sdma_vg10[] = {
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG, 0x0018773f, 0x00104002),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104002),
+ SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831d07),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG, 0x0018773f, 0x00104002),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104002)
};
@@ -103,6 +103,7 @@ static const struct soc15_reg_golden golden_settings_sdma_vg10[] = {
static const struct soc15_reg_golden golden_settings_sdma_vg12[] = {
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG, 0x0018773f, 0x00104001),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104001),
+ SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831d07),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG, 0x0018773f, 0x00104001),
SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104001)
};
@@ -499,7 +500,7 @@ static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
static void sdma_v4_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -833,8 +834,6 @@ static void sdma_v4_0_gfx_resume(struct amdgpu_device *adev, unsigned int i)
OFFSET, ring->doorbell_index);
WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL, doorbell);
WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL_OFFSET, doorbell_offset);
- adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
- ring->doorbell_index);
sdma_v4_0_ring_set_wptr(ring);
@@ -1521,9 +1520,7 @@ static int sdma_v4_0_sw_init(void *handle)
ring->use_doorbell?"true":"false");
/* doorbell size is 2 dwords, get DWORD offset */
- ring->doorbell_index = (i == 0) ?
- (adev->doorbell_index.sdma_engine0 << 1)
- : (adev->doorbell_index.sdma_engine1 << 1);
+ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1;
sprintf(ring->name, "sdma%d", i);
r = amdgpu_ring_init(adev, ring, 1024,
@@ -1542,9 +1539,7 @@ static int sdma_v4_0_sw_init(void *handle)
/* paging queue use same doorbell index/routing as gfx queue
* with 0x400 (4096 dwords) offset on second doorbell page
*/
- ring->doorbell_index = (i == 0) ?
- (adev->doorbell_index.sdma_engine0 << 1)
- : (adev->doorbell_index.sdma_engine1 << 1);
+ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1;
ring->doorbell_index += 0x400;
sprintf(ring->name, "page%d", i);
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index f8408f88cd37..79c1a9bbcc21 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -47,6 +47,7 @@
#include "dce/dce_6_0_d.h"
#include "uvd/uvd_4_0_d.h"
#include "bif/bif_3_0_d.h"
+#include "bif/bif_3_0_sh_mask.h"
static const u32 tahiti_golden_registers[] =
{
@@ -1258,6 +1259,11 @@ static bool si_need_full_reset(struct amdgpu_device *adev)
return true;
}
+static bool si_need_reset_on_init(struct amdgpu_device *adev)
+{
+ return false;
+}
+
static int si_get_pcie_lanes(struct amdgpu_device *adev)
{
u32 link_width_cntl;
@@ -1323,6 +1329,52 @@ static void si_set_pcie_lanes(struct amdgpu_device *adev, int lanes)
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
}
+static void si_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
+ uint64_t *count1)
+{
+ uint32_t perfctr = 0;
+ uint64_t cnt0_of, cnt1_of;
+ int tmp;
+
+ /* This reports 0 on APUs, so return to avoid writing/reading registers
+ * that may or may not be different from their GPU counterparts
+ */
+ if (adev->flags & AMD_IS_APU)
+ return;
+
+ /* Set the 2 events that we wish to watch, defined above */
+ /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+
+ /* Write to enable desired perf counters */
+ WREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK, perfctr);
+ /* Zero out and enable the perf counters
+ * Write 0x5:
+ * Bit 0 = Start all counters(1)
+ * Bit 2 = Global counter reset enable(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000005);
+
+ msleep(1000);
+
+ /* Load the shadow and disable the perf counters
+ * Write 0x2:
+ * Bit 0 = Stop counters(0)
+ * Bit 1 = Load the shadow counters(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000002);
+
+ /* Read register values to get any >32bit overflow */
+ tmp = RREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK);
+ cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER);
+ cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER);
+
+ /* Get the values and add the overflow */
+ *count0 = RREG32_PCIE(ixPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32);
+ *count1 = RREG32_PCIE(ixPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32);
+}
+
static const struct amdgpu_asic_funcs si_asic_funcs =
{
.read_disabled_bios = &si_read_disabled_bios,
@@ -1339,6 +1391,8 @@ static const struct amdgpu_asic_funcs si_asic_funcs =
.flush_hdp = &si_flush_hdp,
.invalidate_hdp = &si_invalidate_hdp,
.need_full_reset = &si_need_full_reset,
+ .get_pcie_usage = &si_get_pcie_usage,
+ .need_reset_on_init = &si_need_reset_on_init,
};
static uint32_t si_get_rev_id(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index b6e473134e19..f15f196684ba 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -63,7 +63,7 @@ static void si_dma_ring_set_wptr(struct amdgpu_ring *ring)
static void si_dma_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c
index 2938fb9f17cc..8c50c9cab455 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c
@@ -57,9 +57,9 @@ static void si_ih_disable_interrupts(struct amdgpu_device *adev)
static int si_ih_irq_init(struct amdgpu_device *adev)
{
+ struct amdgpu_ih_ring *ih = &adev->irq.ih;
int rb_bufsz;
u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
- u64 wptr_off;
si_ih_disable_interrupts(adev);
WREG32(INTERRUPT_CNTL2, adev->irq.ih.gpu_addr >> 8);
@@ -76,9 +76,8 @@ static int si_ih_irq_init(struct amdgpu_device *adev)
(rb_bufsz << 1) |
IH_WPTR_WRITEBACK_ENABLE;
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32(IH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32(IH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
+ WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
WREG32(IH_RB_CNTL, ih_rb_cntl);
WREG32(IH_RB_RPTR, 0);
WREG32(IH_RB_WPTR, 0);
@@ -100,34 +99,36 @@ static void si_ih_irq_disable(struct amdgpu_device *adev)
mdelay(1);
}
-static u32 si_ih_get_wptr(struct amdgpu_device *adev)
+static u32 si_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
u32 wptr, tmp;
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) {
wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK;
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
- adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
+ ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(IH_RB_CNTL);
tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
WREG32(IH_RB_CNTL, tmp);
}
- return (wptr & adev->irq.ih.ptr_mask);
+ return (wptr & ih->ptr_mask);
}
static void si_ih_decode_iv(struct amdgpu_device *adev,
- struct amdgpu_iv_entry *entry)
+ struct amdgpu_ih_ring *ih,
+ struct amdgpu_iv_entry *entry)
{
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[4];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
entry->src_id = dw[0] & 0xff;
@@ -135,12 +136,13 @@ static void si_ih_decode_iv(struct amdgpu_device *adev,
entry->ring_id = dw[2] & 0xff;
entry->vmid = (dw[2] >> 8) & 0xff;
- adev->irq.ih.rptr += 16;
+ ih->rptr += 16;
}
-static void si_ih_set_rptr(struct amdgpu_device *adev)
+static void si_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- WREG32(IH_RB_RPTR, adev->irq.ih.rptr);
+ WREG32(IH_RB_RPTR, ih->rptr);
}
static int si_ih_early_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
index 8849b74078d6..99ebcf29dcb0 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
@@ -43,6 +43,10 @@
#include "hdp/hdp_4_0_sh_mask.h"
#include "smuio/smuio_9_0_offset.h"
#include "smuio/smuio_9_0_sh_mask.h"
+#include "nbio/nbio_7_0_default.h"
+#include "nbio/nbio_7_0_sh_mask.h"
+#include "nbio/nbio_7_0_smn.h"
+#include "mp/mp_9_0_offset.h"
#include "soc15.h"
#include "soc15_common.h"
@@ -385,14 +389,13 @@ void soc15_program_register_sequence(struct amdgpu_device *adev,
}
-
-static int soc15_asic_reset(struct amdgpu_device *adev)
+static int soc15_asic_mode1_reset(struct amdgpu_device *adev)
{
u32 i;
amdgpu_atombios_scratch_regs_engine_hung(adev, true);
- dev_info(adev->dev, "GPU reset\n");
+ dev_info(adev->dev, "GPU mode1 reset\n");
/* disable BM */
pci_clear_master(adev->pdev);
@@ -417,6 +420,63 @@ static int soc15_asic_reset(struct amdgpu_device *adev)
return 0;
}
+static int soc15_asic_get_baco_capability(struct amdgpu_device *adev, bool *cap)
+{
+ void *pp_handle = adev->powerplay.pp_handle;
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+
+ if (!pp_funcs || !pp_funcs->get_asic_baco_capability) {
+ *cap = false;
+ return -ENOENT;
+ }
+
+ return pp_funcs->get_asic_baco_capability(pp_handle, cap);
+}
+
+static int soc15_asic_baco_reset(struct amdgpu_device *adev)
+{
+ void *pp_handle = adev->powerplay.pp_handle;
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+
+ if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state)
+ return -ENOENT;
+
+ /* enter BACO state */
+ if (pp_funcs->set_asic_baco_state(pp_handle, 1))
+ return -EIO;
+
+ /* exit BACO state */
+ if (pp_funcs->set_asic_baco_state(pp_handle, 0))
+ return -EIO;
+
+ dev_info(adev->dev, "GPU BACO reset\n");
+
+ return 0;
+}
+
+static int soc15_asic_reset(struct amdgpu_device *adev)
+{
+ int ret;
+ bool baco_reset;
+
+ switch (adev->asic_type) {
+ case CHIP_VEGA10:
+ case CHIP_VEGA20:
+ soc15_asic_get_baco_capability(adev, &baco_reset);
+ break;
+ default:
+ baco_reset = false;
+ break;
+ }
+
+ if (baco_reset)
+ ret = soc15_asic_baco_reset(adev);
+ else
+ ret = soc15_asic_mode1_reset(adev);
+
+ return ret;
+}
+
/*static int soc15_set_uvd_clock(struct amdgpu_device *adev, u32 clock,
u32 cntl_reg, u32 status_reg)
{
@@ -535,10 +595,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);
amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
- if (adev->asic_type == CHIP_VEGA20)
- amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
- else
- amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
+ if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) {
+ if (adev->asic_type == CHIP_VEGA20)
+ amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
+ else
+ amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
+ }
amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);
amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);
if (!amdgpu_sriov_vf(adev))
@@ -560,7 +622,8 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);
amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);
amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
- amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block);
+ if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP))
+ amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block);
amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);
amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
@@ -601,6 +664,68 @@ static bool soc15_need_full_reset(struct amdgpu_device *adev)
/* change this when we implement soft reset */
return true;
}
+static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
+ uint64_t *count1)
+{
+ uint32_t perfctr = 0;
+ uint64_t cnt0_of, cnt1_of;
+ int tmp;
+
+ /* This reports 0 on APUs, so return to avoid writing/reading registers
+ * that may or may not be different from their GPU counterparts
+ */
+ if (adev->flags & AMD_IS_APU)
+ return;
+
+ /* Set the 2 events that we wish to watch, defined above */
+ /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+
+ /* Write to enable desired perf counters */
+ WREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK, perfctr);
+ /* Zero out and enable the perf counters
+ * Write 0x5:
+ * Bit 0 = Start all counters(1)
+ * Bit 2 = Global counter reset enable(1)
+ */
+ WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000005);
+
+ msleep(1000);
+
+ /* Load the shadow and disable the perf counters
+ * Write 0x2:
+ * Bit 0 = Stop counters(0)
+ * Bit 1 = Load the shadow counters(1)
+ */
+ WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000002);
+
+ /* Read register values to get any >32bit overflow */
+ tmp = RREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK);
+ cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER);
+ cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER);
+
+ /* Get the values and add the overflow */
+ *count0 = RREG32_PCIE(smnPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32);
+ *count1 = RREG32_PCIE(smnPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32);
+}
+
+static bool soc15_need_reset_on_init(struct amdgpu_device *adev)
+{
+ u32 sol_reg;
+
+ if (adev->flags & AMD_IS_APU)
+ return false;
+
+ /* Check sOS sign of life register to confirm sys driver and sOS
+ * are already been loaded.
+ */
+ sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
+ if (sol_reg)
+ return true;
+
+ return false;
+}
static const struct amdgpu_asic_funcs soc15_asic_funcs =
{
@@ -617,6 +742,8 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =
.invalidate_hdp = &soc15_invalidate_hdp,
.need_full_reset = &soc15_need_full_reset,
.init_doorbell_index = &vega10_doorbell_index_init,
+ .get_pcie_usage = &soc15_get_pcie_usage,
+ .need_reset_on_init = &soc15_need_reset_on_init,
};
static const struct amdgpu_asic_funcs vega20_asic_funcs =
@@ -634,6 +761,8 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs =
.invalidate_hdp = &soc15_invalidate_hdp,
.need_full_reset = &soc15_need_full_reset,
.init_doorbell_index = &vega20_doorbell_index_init,
+ .get_pcie_usage = &soc15_get_pcie_usage,
+ .need_reset_on_init = &soc15_need_reset_on_init,
};
static int soc15_common_early_init(void *handle)
@@ -729,11 +858,13 @@ static int soc15_common_early_init(void *handle)
case CHIP_RAVEN:
adev->asic_funcs = &soc15_asic_funcs;
if (adev->rev_id >= 0x8)
- adev->external_rev_id = adev->rev_id + 0x81;
+ adev->external_rev_id = adev->rev_id + 0x79;
else if (adev->pdev->device == 0x15d8)
adev->external_rev_id = adev->rev_id + 0x41;
+ else if (adev->rev_id == 1)
+ adev->external_rev_id = adev->rev_id + 0x20;
else
- adev->external_rev_id = 0x1;
+ adev->external_rev_id = adev->rev_id + 0x01;
if (adev->rev_id >= 0x8) {
adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
@@ -840,6 +971,22 @@ static int soc15_common_sw_fini(void *handle)
return 0;
}
+static void soc15_doorbell_range_init(struct amdgpu_device *adev)
+{
+ int i;
+ struct amdgpu_ring *ring;
+
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ ring = &adev->sdma.instance[i].ring;
+ adev->nbio_funcs->sdma_doorbell_range(adev, i,
+ ring->use_doorbell, ring->doorbell_index,
+ adev->doorbell_index.sdma_doorbell_range);
+ }
+
+ adev->nbio_funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
+ adev->irq.ih.doorbell_index);
+}
+
static int soc15_common_hw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -852,6 +999,12 @@ static int soc15_common_hw_init(void *handle)
adev->nbio_funcs->init_registers(adev);
/* enable the doorbell aperture */
soc15_enable_doorbell_aperture(adev, true);
+ /* HW doorbell routing policy: doorbell writing not
+ * in SDMA/IH/MM/ACV range will be routed to CP. So
+ * we need to init SDMA/IH/MM/ACV doorbell range prior
+ * to CP ip block init and ring test.
+ */
+ soc15_doorbell_range_init(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
index 15da06ddeb75..a20b711a6756 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -99,9 +99,9 @@ static void tonga_ih_disable_interrupts(struct amdgpu_device *adev)
*/
static int tonga_ih_irq_init(struct amdgpu_device *adev)
{
- int rb_bufsz;
u32 interrupt_cntl, ih_rb_cntl, ih_doorbell_rtpr;
- u64 wptr_off;
+ struct amdgpu_ih_ring *ih = &adev->irq.ih;
+ int rb_bufsz;
/* disable irqs */
tonga_ih_disable_interrupts(adev);
@@ -118,10 +118,7 @@ static int tonga_ih_irq_init(struct amdgpu_device *adev)
WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
- if (adev->irq.ih.use_bus_addr)
- WREG32(mmIH_RB_BASE, adev->irq.ih.rb_dma_addr >> 8);
- else
- WREG32(mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
+ WREG32(mmIH_RB_BASE, ih->gpu_addr >> 8);
rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
ih_rb_cntl = REG_SET_FIELD(0, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
@@ -136,12 +133,8 @@ static int tonga_ih_irq_init(struct amdgpu_device *adev)
WREG32(mmIH_RB_CNTL, ih_rb_cntl);
/* set the writeback address whether it's enabled or not */
- if (adev->irq.ih.use_bus_addr)
- wptr_off = adev->irq.ih.rb_dma_addr + (adev->irq.ih.wptr_offs * 4);
- else
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(ih->wptr_addr));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(ih->wptr_addr) & 0xFF);
/* set rptr, wptr to 0 */
WREG32(mmIH_RB_RPTR, 0);
@@ -193,14 +186,12 @@ static void tonga_ih_irq_disable(struct amdgpu_device *adev)
* Used by cz_irq_process(VI).
* Returns the value of the wptr.
*/
-static u32 tonga_ih_get_wptr(struct amdgpu_device *adev)
+static u32 tonga_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
u32 wptr, tmp;
- if (adev->irq.ih.use_bus_addr)
- wptr = le32_to_cpu(adev->irq.ih.ring[adev->irq.ih.wptr_offs]);
- else
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
@@ -209,13 +200,13 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev)
* this should allow us to catchup.
*/
dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
- adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ wptr, ih->rptr, (wptr + 16) & ih->ptr_mask);
+ ih->rptr = (wptr + 16) & ih->ptr_mask;
tmp = RREG32(mmIH_RB_CNTL);
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
WREG32(mmIH_RB_CNTL, tmp);
}
- return (wptr & adev->irq.ih.ptr_mask);
+ return (wptr & ih->ptr_mask);
}
/**
@@ -227,16 +218,17 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev)
* position and also advance the position.
*/
static void tonga_ih_decode_iv(struct amdgpu_device *adev,
- struct amdgpu_iv_entry *entry)
+ struct amdgpu_ih_ring *ih,
+ struct amdgpu_iv_entry *entry)
{
/* wptr/rptr are in bytes! */
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[4];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
entry->client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
entry->src_id = dw[0] & 0xff;
@@ -246,7 +238,7 @@ static void tonga_ih_decode_iv(struct amdgpu_device *adev,
entry->pasid = (dw[2] >> 16) & 0xffff;
/* wptr/rptr are in bytes! */
- adev->irq.ih.rptr += 16;
+ ih->rptr += 16;
}
/**
@@ -256,17 +248,15 @@ static void tonga_ih_decode_iv(struct amdgpu_device *adev,
*
* Set the IH ring buffer rptr.
*/
-static void tonga_ih_set_rptr(struct amdgpu_device *adev)
+static void tonga_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- if (adev->irq.ih.use_doorbell) {
+ if (ih->use_doorbell) {
/* XXX check if swapping is necessary on BE */
- if (adev->irq.ih.use_bus_addr)
- adev->irq.ih.ring[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
- else
- adev->wb.wb[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
- WDOORBELL32(adev->irq.ih.doorbell_index, adev->irq.ih.rptr);
+ *ih->rptr_cpu = ih->rptr;
+ WDOORBELL32(ih->doorbell_index, ih->rptr);
} else {
- WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+ WREG32(mmIH_RB_RPTR, ih->rptr);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
index d69c8f6daaf8..c4fb58667fd4 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -511,7 +511,7 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
static void uvd_v4_2_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_BASE, 0));
amdgpu_ring_write(ring, ib->gpu_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
index ee8cd06ddc38..52bd8a654734 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
@@ -526,7 +526,7 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_64BIT_BAR_LOW, 0));
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index d4f4a66f8324..c9edddf9f88a 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -977,7 +977,7 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -1003,7 +1003,7 @@ static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
static void uvd_v6_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
index aef924026a28..dc461df48da0 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
@@ -1272,7 +1272,7 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -1303,7 +1303,7 @@ static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
static void uvd_v7_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 2668effadd27..6ec65cf11112 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -834,7 +834,7 @@ out:
static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
index 9fb34b7d8e03..aadc3e66ebd7 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
@@ -947,7 +947,7 @@ static int vce_v4_0_set_powergating_state(void *handle,
#endif
static void vce_v4_0_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
- struct amdgpu_ib *ib, bool ctx_switch)
+ struct amdgpu_ib *ib, uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 89bb2fef90eb..3dbc51f9d3b9 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -1371,7 +1371,7 @@ static void vcn_v1_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64
static void vcn_v1_0_dec_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -1531,7 +1531,7 @@ static void vcn_v1_0_enc_ring_insert_end(struct amdgpu_ring *ring)
static void vcn_v1_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
@@ -1736,7 +1736,7 @@ static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u6
static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_job *job,
struct amdgpu_ib *ib,
- bool ctx_switch)
+ uint32_t flags)
{
struct amdgpu_device *adev = ring->adev;
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
index 2c250b01a903..6d1f804277f8 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
@@ -50,6 +50,22 @@ static void vega10_ih_enable_interrupts(struct amdgpu_device *adev)
ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
adev->irq.ih.enabled = true;
+
+ if (adev->irq.ih1.ring_size) {
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
+ RB_ENABLE, 1);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+ adev->irq.ih1.enabled = true;
+ }
+
+ if (adev->irq.ih2.ring_size) {
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
+ RB_ENABLE, 1);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+ adev->irq.ih2.enabled = true;
+ }
}
/**
@@ -71,6 +87,53 @@ static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
adev->irq.ih.enabled = false;
adev->irq.ih.rptr = 0;
+
+ if (adev->irq.ih1.ring_size) {
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
+ RB_ENABLE, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+ /* set rptr, wptr to 0 */
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
+ adev->irq.ih1.enabled = false;
+ adev->irq.ih1.rptr = 0;
+ }
+
+ if (adev->irq.ih2.ring_size) {
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
+ RB_ENABLE, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+ /* set rptr, wptr to 0 */
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
+ adev->irq.ih2.enabled = false;
+ adev->irq.ih2.rptr = 0;
+ }
+}
+
+static uint32_t vega10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
+{
+ int rb_bufsz = order_base_2(ih->ring_size / 4);
+
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+ MC_SPACE, ih->use_bus_addr ? 1 : 4);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+ WPTR_OVERFLOW_CLEAR, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+ WPTR_OVERFLOW_ENABLE, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
+ /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register
+ * value is written to memory
+ */
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+ WPTR_WRITEBACK_ENABLE, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
+
+ return ih_rb_cntl;
}
/**
@@ -86,50 +149,32 @@ static void vega10_ih_disable_interrupts(struct amdgpu_device *adev)
*/
static int vega10_ih_irq_init(struct amdgpu_device *adev)
{
+ struct amdgpu_ih_ring *ih;
int ret = 0;
- int rb_bufsz;
u32 ih_rb_cntl, ih_doorbell_rtpr;
u32 tmp;
- u64 wptr_off;
/* disable irqs */
vega10_ih_disable_interrupts(adev);
adev->nbio_funcs->ih_control(adev);
- ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
+ ih = &adev->irq.ih;
/* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
- if (adev->irq.ih.use_bus_addr) {
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, adev->irq.ih.rb_dma_addr >> 8);
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, ((u64)adev->irq.ih.rb_dma_addr >> 40) & 0xff);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 1);
- } else {
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (adev->irq.ih.gpu_addr >> 40) & 0xff);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SPACE, 4);
- }
- rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 1);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
- /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
-
- if (adev->irq.msi_enabled)
- ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM, 1);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE, ih->gpu_addr >> 8);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI, (ih->gpu_addr >> 40) & 0xff);
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL);
+ ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RPTR_REARM,
+ !!adev->irq.msi_enabled);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
/* set the writeback address whether it's enabled or not */
- if (adev->irq.ih.use_bus_addr)
- wptr_off = adev->irq.ih.rb_dma_addr + (adev->irq.ih.wptr_offs * 4);
- else
- wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFFFF);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO,
+ lower_32_bits(ih->wptr_addr));
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI,
+ upper_32_bits(ih->wptr_addr) & 0xFFFF);
/* set rptr, wptr to 0 */
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
@@ -137,17 +182,48 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)
ih_doorbell_rtpr = RREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR);
if (adev->irq.ih.use_doorbell) {
- ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
- OFFSET, adev->irq.ih.doorbell_index);
- ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
+ ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+ IH_DOORBELL_RPTR, OFFSET,
+ adev->irq.ih.doorbell_index);
+ ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+ IH_DOORBELL_RPTR,
ENABLE, 1);
} else {
- ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr, IH_DOORBELL_RPTR,
+ ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+ IH_DOORBELL_RPTR,
ENABLE, 0);
}
WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR, ih_doorbell_rtpr);
- adev->nbio_funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
- adev->irq.ih.doorbell_index);
+
+ ih = &adev->irq.ih1;
+ if (ih->ring_size) {
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING1, ih->gpu_addr >> 8);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING1,
+ (ih->gpu_addr >> 40) & 0xff);
+
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+ ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+
+ /* set rptr, wptr to 0 */
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
+ }
+
+ ih = &adev->irq.ih2;
+ if (ih->ring_size) {
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING2, ih->gpu_addr >> 8);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING2,
+ (ih->gpu_addr >> 40) & 0xff);
+
+ ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+ ih_rb_cntl = vega10_ih_rb_cntl(ih, ih_rb_cntl);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+
+ /* set rptr, wptr to 0 */
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
+ }
tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,
@@ -191,32 +267,58 @@ static void vega10_ih_irq_disable(struct amdgpu_device *adev)
* ring buffer overflow and deal with it.
* Returns the value of the wptr.
*/
-static u32 vega10_ih_get_wptr(struct amdgpu_device *adev)
+static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- u32 wptr, tmp;
+ u32 wptr, reg, tmp;
- if (adev->irq.ih.use_bus_addr)
- wptr = le32_to_cpu(adev->irq.ih.ring[adev->irq.ih.wptr_offs]);
+ wptr = le32_to_cpu(*ih->wptr_cpu);
+
+ if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+ goto out;
+
+ /* Double check that the overflow wasn't already cleared. */
+
+ if (ih == &adev->irq.ih)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
+ else if (ih == &adev->irq.ih1)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
+ else if (ih == &adev->irq.ih2)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
else
- wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
-
- if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
- wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
-
- /* When a ring buffer overflow happen start parsing interrupt
- * from the last not overwritten vector (wptr + 32). Hopefully
- * this should allow us to catchup.
- */
- tmp = (wptr + 32) & adev->irq.ih.ptr_mask;
- dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
- wptr, adev->irq.ih.rptr, tmp);
- adev->irq.ih.rptr = tmp;
-
- tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL));
- tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
- WREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp);
- }
- return (wptr & adev->irq.ih.ptr_mask);
+ BUG();
+
+ wptr = RREG32_NO_KIQ(reg);
+ if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
+ goto out;
+
+ wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
+
+ /* When a ring buffer overflow happen start parsing interrupt
+ * from the last not overwritten vector (wptr + 32). Hopefully
+ * this should allow us to catchup.
+ */
+ tmp = (wptr + 32) & ih->ptr_mask;
+ dev_warn(adev->dev, "IH ring buffer overflow "
+ "(0x%08X, 0x%08X, 0x%08X)\n",
+ wptr, ih->rptr, tmp);
+ ih->rptr = tmp;
+
+ if (ih == &adev->irq.ih)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
+ else if (ih == &adev->irq.ih1)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+ else if (ih == &adev->irq.ih2)
+ reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+ else
+ BUG();
+
+ tmp = RREG32_NO_KIQ(reg);
+ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+ WREG32_NO_KIQ(reg, tmp);
+
+out:
+ return (wptr & ih->ptr_mask);
}
/**
@@ -228,20 +330,21 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev)
* position and also advance the position.
*/
static void vega10_ih_decode_iv(struct amdgpu_device *adev,
- struct amdgpu_iv_entry *entry)
+ struct amdgpu_ih_ring *ih,
+ struct amdgpu_iv_entry *entry)
{
/* wptr/rptr are in bytes! */
- u32 ring_index = adev->irq.ih.rptr >> 2;
+ u32 ring_index = ih->rptr >> 2;
uint32_t dw[8];
- dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
- dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
- dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
- dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
- dw[4] = le32_to_cpu(adev->irq.ih.ring[ring_index + 4]);
- dw[5] = le32_to_cpu(adev->irq.ih.ring[ring_index + 5]);
- dw[6] = le32_to_cpu(adev->irq.ih.ring[ring_index + 6]);
- dw[7] = le32_to_cpu(adev->irq.ih.ring[ring_index + 7]);
+ dw[0] = le32_to_cpu(ih->ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(ih->ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(ih->ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(ih->ring[ring_index + 3]);
+ dw[4] = le32_to_cpu(ih->ring[ring_index + 4]);
+ dw[5] = le32_to_cpu(ih->ring[ring_index + 5]);
+ dw[6] = le32_to_cpu(ih->ring[ring_index + 6]);
+ dw[7] = le32_to_cpu(ih->ring[ring_index + 7]);
entry->client_id = dw[0] & 0xff;
entry->src_id = (dw[0] >> 8) & 0xff;
@@ -257,9 +360,8 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,
entry->src_data[2] = dw[6];
entry->src_data[3] = dw[7];
-
/* wptr/rptr are in bytes! */
- adev->irq.ih.rptr += 32;
+ ih->rptr += 32;
}
/**
@@ -269,37 +371,95 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,
*
* Set the IH ring buffer rptr.
*/
-static void vega10_ih_set_rptr(struct amdgpu_device *adev)
+static void vega10_ih_set_rptr(struct amdgpu_device *adev,
+ struct amdgpu_ih_ring *ih)
{
- if (adev->irq.ih.use_doorbell) {
+ if (ih->use_doorbell) {
/* XXX check if swapping is necessary on BE */
- if (adev->irq.ih.use_bus_addr)
- adev->irq.ih.ring[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
- else
- adev->wb.wb[adev->irq.ih.rptr_offs] = adev->irq.ih.rptr;
- WDOORBELL32(adev->irq.ih.doorbell_index, adev->irq.ih.rptr);
- } else {
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, adev->irq.ih.rptr);
+ *ih->rptr_cpu = ih->rptr;
+ WDOORBELL32(ih->doorbell_index, ih->rptr);
+ } else if (ih == &adev->irq.ih) {
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
+ } else if (ih == &adev->irq.ih1) {
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, ih->rptr);
+ } else if (ih == &adev->irq.ih2) {
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, ih->rptr);
}
}
+/**
+ * vega10_ih_self_irq - dispatch work for ring 1 and 2
+ *
+ * @adev: amdgpu_device pointer
+ * @source: irq source
+ * @entry: IV with WPTR update
+ *
+ * Update the WPTR from the IV and schedule work to handle the entries.
+ */
+static int vega10_ih_self_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ uint32_t wptr = cpu_to_le32(entry->src_data[0]);
+
+ switch (entry->ring_id) {
+ case 1:
+ *adev->irq.ih1.wptr_cpu = wptr;
+ schedule_work(&adev->irq.ih1_work);
+ break;
+ case 2:
+ *adev->irq.ih2.wptr_cpu = wptr;
+ schedule_work(&adev->irq.ih2_work);
+ break;
+ default: break;
+ }
+ return 0;
+}
+
+static const struct amdgpu_irq_src_funcs vega10_ih_self_irq_funcs = {
+ .process = vega10_ih_self_irq,
+};
+
+static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev)
+{
+ adev->irq.self_irq.num_types = 0;
+ adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs;
+}
+
static int vega10_ih_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
vega10_ih_set_interrupt_funcs(adev);
+ vega10_ih_set_self_irq_funcs(adev);
return 0;
}
static int vega10_ih_sw_init(void *handle)
{
- int r;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int r;
+
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
+ &adev->irq.self_irq);
+ if (r)
+ return r;
r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);
if (r)
return r;
+ if (adev->asic_type == CHIP_VEGA10) {
+ r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
+ if (r)
+ return r;
+
+ r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
+ if (r)
+ return r;
+ }
+
+ /* TODO add doorbell for IH1 & IH2 as well */
adev->irq.ih.use_doorbell = true;
adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
@@ -313,6 +473,8 @@ static int vega10_ih_sw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
amdgpu_irq_fini(adev);
+ amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
+ amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
amdgpu_ih_ring_fini(adev, &adev->irq.ih);
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c
index 422674bb3cdf..4b5d60ea3e78 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c
@@ -70,8 +70,8 @@ void vega10_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.userqueue_start = AMDGPU_DOORBELL64_USERQUEUE_START;
adev->doorbell_index.userqueue_end = AMDGPU_DOORBELL64_USERQUEUE_END;
adev->doorbell_index.gfx_ring0 = AMDGPU_DOORBELL64_GFX_RING0;
- adev->doorbell_index.sdma_engine0 = AMDGPU_DOORBELL64_sDMA_ENGINE0;
- adev->doorbell_index.sdma_engine1 = AMDGPU_DOORBELL64_sDMA_ENGINE1;
+ adev->doorbell_index.sdma_engine[0] = AMDGPU_DOORBELL64_sDMA_ENGINE0;
+ adev->doorbell_index.sdma_engine[1] = AMDGPU_DOORBELL64_sDMA_ENGINE1;
adev->doorbell_index.ih = AMDGPU_DOORBELL64_IH;
adev->doorbell_index.uvd_vce.uvd_ring0_1 = AMDGPU_DOORBELL64_UVD_RING0_1;
adev->doorbell_index.uvd_vce.uvd_ring2_3 = AMDGPU_DOORBELL64_UVD_RING2_3;
@@ -83,5 +83,6 @@ void vega10_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.uvd_vce.vce_ring6_7 = AMDGPU_DOORBELL64_VCE_RING6_7;
/* In unit of dword doorbell */
adev->doorbell_index.max_assignment = AMDGPU_DOORBELL64_MAX_ASSIGNMENT << 1;
+ adev->doorbell_index.sdma_doorbell_range = 4;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
index edce413fda9a..53716c593b2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
@@ -68,14 +68,14 @@ void vega20_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.userqueue_start = AMDGPU_VEGA20_DOORBELL_USERQUEUE_START;
adev->doorbell_index.userqueue_end = AMDGPU_VEGA20_DOORBELL_USERQUEUE_END;
adev->doorbell_index.gfx_ring0 = AMDGPU_VEGA20_DOORBELL_GFX_RING0;
- adev->doorbell_index.sdma_engine0 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE0;
- adev->doorbell_index.sdma_engine1 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE1;
- adev->doorbell_index.sdma_engine2 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE2;
- adev->doorbell_index.sdma_engine3 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE3;
- adev->doorbell_index.sdma_engine4 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE4;
- adev->doorbell_index.sdma_engine5 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE5;
- adev->doorbell_index.sdma_engine6 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE6;
- adev->doorbell_index.sdma_engine7 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE7;
+ adev->doorbell_index.sdma_engine[0] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE0;
+ adev->doorbell_index.sdma_engine[1] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE1;
+ adev->doorbell_index.sdma_engine[2] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE2;
+ adev->doorbell_index.sdma_engine[3] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE3;
+ adev->doorbell_index.sdma_engine[4] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE4;
+ adev->doorbell_index.sdma_engine[5] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE5;
+ adev->doorbell_index.sdma_engine[6] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE6;
+ adev->doorbell_index.sdma_engine[7] = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE7;
adev->doorbell_index.ih = AMDGPU_VEGA20_DOORBELL_IH;
adev->doorbell_index.uvd_vce.uvd_ring0_1 = AMDGPU_VEGA20_DOORBELL64_UVD_RING0_1;
adev->doorbell_index.uvd_vce.uvd_ring2_3 = AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3;
@@ -86,5 +86,6 @@ void vega20_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.uvd_vce.vce_ring4_5 = AMDGPU_VEGA20_DOORBELL64_VCE_RING4_5;
adev->doorbell_index.uvd_vce.vce_ring6_7 = AMDGPU_VEGA20_DOORBELL64_VCE_RING6_7;
adev->doorbell_index.max_assignment = AMDGPU_VEGA20_DOORBELL_MAX_ASSIGNMENT << 1;
+ adev->doorbell_index.sdma_doorbell_range = 20;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index 77e367459101..5e5b42a0744a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -941,6 +941,69 @@ static bool vi_need_full_reset(struct amdgpu_device *adev)
}
}
+static void vi_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
+ uint64_t *count1)
+{
+ uint32_t perfctr = 0;
+ uint64_t cnt0_of, cnt1_of;
+ int tmp;
+
+ /* This reports 0 on APUs, so return to avoid writing/reading registers
+ * that may or may not be different from their GPU counterparts
+ */
+ if (adev->flags & AMD_IS_APU)
+ return;
+
+ /* Set the 2 events that we wish to watch, defined above */
+ /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
+ perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+
+ /* Write to enable desired perf counters */
+ WREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK, perfctr);
+ /* Zero out and enable the perf counters
+ * Write 0x5:
+ * Bit 0 = Start all counters(1)
+ * Bit 2 = Global counter reset enable(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000005);
+
+ msleep(1000);
+
+ /* Load the shadow and disable the perf counters
+ * Write 0x2:
+ * Bit 0 = Stop counters(0)
+ * Bit 1 = Load the shadow counters(1)
+ */
+ WREG32_PCIE(ixPCIE_PERF_COUNT_CNTL, 0x00000002);
+
+ /* Read register values to get any >32bit overflow */
+ tmp = RREG32_PCIE(ixPCIE_PERF_CNTL_TXCLK);
+ cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER);
+ cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER);
+
+ /* Get the values and add the overflow */
+ *count0 = RREG32_PCIE(ixPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32);
+ *count1 = RREG32_PCIE(ixPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32);
+}
+
+static bool vi_need_reset_on_init(struct amdgpu_device *adev)
+{
+ u32 clock_cntl, pc;
+
+ if (adev->flags & AMD_IS_APU)
+ return false;
+
+ /* check if the SMC is already running */
+ clock_cntl = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+ pc = RREG32_SMC(ixSMC_PC_C);
+ if ((0 == REG_GET_FIELD(clock_cntl, SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) &&
+ (0x20100 <= pc))
+ return true;
+
+ return false;
+}
+
static const struct amdgpu_asic_funcs vi_asic_funcs =
{
.read_disabled_bios = &vi_read_disabled_bios,
@@ -956,6 +1019,8 @@ static const struct amdgpu_asic_funcs vi_asic_funcs =
.invalidate_hdp = &vi_invalidate_hdp,
.need_full_reset = &vi_need_full_reset,
.init_doorbell_index = &legacy_doorbell_index_init,
+ .get_pcie_usage = &vi_get_pcie_usage,
+ .need_reset_on_init = &vi_need_reset_on_init,
};
#define CZ_REV_BRISTOL(rev) \
@@ -1726,8 +1791,8 @@ void legacy_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.mec_ring6 = AMDGPU_DOORBELL_MEC_RING6;
adev->doorbell_index.mec_ring7 = AMDGPU_DOORBELL_MEC_RING7;
adev->doorbell_index.gfx_ring0 = AMDGPU_DOORBELL_GFX_RING0;
- adev->doorbell_index.sdma_engine0 = AMDGPU_DOORBELL_sDMA_ENGINE0;
- adev->doorbell_index.sdma_engine1 = AMDGPU_DOORBELL_sDMA_ENGINE1;
+ adev->doorbell_index.sdma_engine[0] = AMDGPU_DOORBELL_sDMA_ENGINE0;
+ adev->doorbell_index.sdma_engine[1] = AMDGPU_DOORBELL_sDMA_ENGINE1;
adev->doorbell_index.ih = AMDGPU_DOORBELL_IH;
adev->doorbell_index.max_assignment = AMDGPU_DOORBELL_MAX_ASSIGNMENT;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig
index fbf0ee5201c3..c3613604a4f8 100644
--- a/drivers/gpu/drm/amd/amdkfd/Kconfig
+++ b/drivers/gpu/drm/amd/amdkfd/Kconfig
@@ -4,8 +4,8 @@
config HSA_AMD
bool "HSA kernel driver for AMD GPU devices"
- depends on DRM_AMDGPU && X86_64
- imply AMD_IOMMU_V2
+ depends on DRM_AMDGPU && (X86_64 || ARM64)
+ imply AMD_IOMMU_V2 if X86_64
select MMU_NOTIFIER
help
Enable this if you want to use HSA features on AMD GPU devices.
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index b7bc7d7d048f..2e7c44955f43 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -863,6 +863,7 @@ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size,
return 0;
}
+#ifdef CONFIG_X86_64
static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size,
uint32_t *num_entries,
struct crat_subtype_iolink *sub_type_hdr)
@@ -905,6 +906,7 @@ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size,
return 0;
}
+#endif
/* kfd_create_vcrat_image_cpu - Create Virtual CRAT for CPU
*
@@ -920,7 +922,9 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
struct crat_subtype_generic *sub_type_hdr;
int avail_size = *size;
int numa_node_id;
+#ifdef CONFIG_X86_64
uint32_t entries = 0;
+#endif
int ret = 0;
if (!pcrat_image || avail_size < VCRAT_SIZE_FOR_CPU)
@@ -982,6 +986,7 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
sub_type_hdr->length);
/* Fill in Subtype: IO Link */
+#ifdef CONFIG_X86_64
ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size,
&entries,
(struct crat_subtype_iolink *)sub_type_hdr);
@@ -992,6 +997,9 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
sub_type_hdr->length * entries);
+#else
+ pr_info("IO link not available for non x86 platforms\n");
+#endif
crat_table->num_domains++;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
index 8018163414ff..932007eb9168 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
@@ -23,22 +23,7 @@
#include <linux/sched.h>
#include <linux/device.h>
#include "kfd_priv.h"
-
-static const struct kgd2kfd_calls kgd2kfd = {
- .exit = kgd2kfd_exit,
- .probe = kgd2kfd_probe,
- .device_init = kgd2kfd_device_init,
- .device_exit = kgd2kfd_device_exit,
- .interrupt = kgd2kfd_interrupt,
- .suspend = kgd2kfd_suspend,
- .resume = kgd2kfd_resume,
- .quiesce_mm = kgd2kfd_quiesce_mm,
- .resume_mm = kgd2kfd_resume_mm,
- .schedule_evict_and_restore_process =
- kgd2kfd_schedule_evict_and_restore_process,
- .pre_reset = kgd2kfd_pre_reset,
- .post_reset = kgd2kfd_post_reset,
-};
+#include "amdgpu_amdkfd.h"
static int kfd_init(void)
{
@@ -91,20 +76,10 @@ static void kfd_exit(void)
kfd_chardev_exit();
}
-int kgd2kfd_init(unsigned int interface_version,
- const struct kgd2kfd_calls **g2f)
+int kgd2kfd_init()
{
- int err;
-
- err = kfd_init();
- if (err)
- return err;
-
- *g2f = &kgd2kfd;
-
- return 0;
+ return kfd_init();
}
-EXPORT_SYMBOL(kgd2kfd_init);
void kgd2kfd_exit(void)
{
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 0689d4ccbbc0..12b66330fc6d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -266,14 +266,6 @@ struct kfd_dev {
bool pci_atomic_requested;
};
-/* KGD2KFD callbacks */
-void kgd2kfd_exit(void);
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
- struct pci_dev *pdev, const struct kfd2kgd_calls *f2g);
-bool kgd2kfd_device_init(struct kfd_dev *kfd,
- const struct kgd2kfd_shared_resources *gpu_resources);
-void kgd2kfd_device_exit(struct kfd_dev *kfd);
-
enum kfd_mempool {
KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -541,11 +533,6 @@ struct qcm_process_device {
/* Approx. time before evicting the process again */
#define PROCESS_ACTIVE_TIME_MS 10
-int kgd2kfd_quiesce_mm(struct mm_struct *mm);
-int kgd2kfd_resume_mm(struct mm_struct *mm);
-int kgd2kfd_schedule_evict_and_restore_process(struct mm_struct *mm,
- struct dma_fence *fence);
-
/* 8 byte handle containing GPU ID in the most significant 4 bytes and
* idr_handle in the least significant 4 bytes
*/
@@ -800,20 +787,11 @@ int kfd_numa_node_to_apic_id(int numa_node_id);
/* Interrupts */
int kfd_interrupt_init(struct kfd_dev *dev);
void kfd_interrupt_exit(struct kfd_dev *dev);
-void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
bool enqueue_ih_ring_entry(struct kfd_dev *kfd, const void *ih_ring_entry);
bool interrupt_is_wanted(struct kfd_dev *dev,
const uint32_t *ih_ring_entry,
uint32_t *patched_ihre, bool *flag);
-/* Power Management */
-void kgd2kfd_suspend(struct kfd_dev *kfd);
-int kgd2kfd_resume(struct kfd_dev *kfd);
-
-/* GPU reset */
-int kgd2kfd_pre_reset(struct kfd_dev *kfd);
-int kgd2kfd_post_reset(struct kfd_dev *kfd);
-
/* amdkfd Apertures */
int kfd_init_apertures(struct kfd_process *process);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index 5f5b2acedbac..09da91644f9f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -1093,8 +1093,6 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
* the GPU device is not already present in the topology device
* list then return NULL. This means a new topology device has to
* be created for this GPU.
- * TODO: Rather than assiging @gpu to first topology device withtout
- * gpu attached, it will better to have more stringent check.
*/
static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu)
{
@@ -1102,12 +1100,20 @@ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu)
struct kfd_topology_device *out_dev = NULL;
down_write(&topology_lock);
- list_for_each_entry(dev, &topology_device_list, list)
+ list_for_each_entry(dev, &topology_device_list, list) {
+ /* Discrete GPUs need their own topology device list
+ * entries. Don't assign them to CPU/APU nodes.
+ */
+ if (!gpu->device_info->needs_iommu_device &&
+ dev->node_props.cpu_cores_count)
+ continue;
+
if (!dev->gpu && (dev->node_props.simd_count > 0)) {
dev->gpu = gpu;
out_dev = dev;
break;
}
+ }
up_write(&topology_lock);
return out_dev;
}
@@ -1392,7 +1398,6 @@ int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev)
static int kfd_cpumask_to_apic_id(const struct cpumask *cpumask)
{
- const struct cpuinfo_x86 *cpuinfo;
int first_cpu_of_numa_node;
if (!cpumask || cpumask == cpu_none_mask)
@@ -1400,9 +1405,11 @@ static int kfd_cpumask_to_apic_id(const struct cpumask *cpumask)
first_cpu_of_numa_node = cpumask_first(cpumask);
if (first_cpu_of_numa_node >= nr_cpu_ids)
return -1;
- cpuinfo = &cpu_data(first_cpu_of_numa_node);
-
- return cpuinfo->apicid;
+#ifdef CONFIG_X86_64
+ return cpu_data(first_cpu_of_numa_node).apicid;
+#else
+ return first_cpu_of_numa_node;
+#endif
}
/* kfd_numa_node_to_apic_id - Returns the APIC ID of the first logical processor
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 8a626d16e8e3..3a6f595f295e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -699,22 +699,36 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
{
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
+ struct drm_dp_mst_topology_mgr *mgr;
+ int ret;
+ bool need_hotplug = false;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- aconnector = to_amdgpu_dm_connector(connector);
- if (aconnector->dc_link->type == dc_connection_mst_branch &&
- !aconnector->mst_port) {
+ list_for_each_entry(connector, &dev->mode_config.connector_list,
+ head) {
+ aconnector = to_amdgpu_dm_connector(connector);
+ if (aconnector->dc_link->type != dc_connection_mst_branch ||
+ aconnector->mst_port)
+ continue;
- if (suspend)
- drm_dp_mst_topology_mgr_suspend(&aconnector->mst_mgr);
- else
- drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr);
- }
+ mgr = &aconnector->mst_mgr;
+
+ if (suspend) {
+ drm_dp_mst_topology_mgr_suspend(mgr);
+ } else {
+ ret = drm_dp_mst_topology_mgr_resume(mgr);
+ if (ret < 0) {
+ drm_dp_mst_topology_mgr_set_mst(mgr, false);
+ need_hotplug = true;
+ }
+ }
}
drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+ if (need_hotplug)
+ drm_kms_helper_hotplug_event(dev);
}
/**
@@ -898,7 +912,6 @@ static int dm_resume(void *handle)
struct drm_plane_state *new_plane_state;
struct dm_plane_state *dm_new_plane_state;
enum dc_connection_type new_connection_type = dc_connection_none;
- int ret;
int i;
/* power on hardware */
@@ -971,13 +984,13 @@ static int dm_resume(void *handle)
}
}
- ret = drm_atomic_helper_resume(ddev, dm->cached_state);
+ drm_atomic_helper_resume(ddev, dm->cached_state);
dm->cached_state = NULL;
amdgpu_dm_irq_resume_late(adev);
- return ret;
+ return 0;
}
/**
@@ -1760,7 +1773,7 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
+ caps.min_input_signal * 0x101;
if (dc_link_set_backlight_level(dm->backlight_link,
- brightness, 0, 0))
+ brightness, 0))
return 0;
else
return 1;
@@ -2284,6 +2297,71 @@ static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
return r;
}
+static inline uint64_t get_dcc_address(uint64_t address, uint64_t tiling_flags)
+{
+ uint32_t offset = AMDGPU_TILING_GET(tiling_flags, DCC_OFFSET_256B);
+
+ return offset ? (address + offset * 256) : 0;
+}
+
+static bool fill_plane_dcc_attributes(struct amdgpu_device *adev,
+ const struct amdgpu_framebuffer *afb,
+ struct dc_plane_state *plane_state,
+ uint64_t info)
+{
+ struct dc *dc = adev->dm.dc;
+ struct dc_dcc_surface_param input;
+ struct dc_surface_dcc_cap output;
+ uint32_t offset = AMDGPU_TILING_GET(info, DCC_OFFSET_256B);
+ uint32_t i64b = AMDGPU_TILING_GET(info, DCC_INDEPENDENT_64B) != 0;
+ uint64_t dcc_address;
+
+ memset(&input, 0, sizeof(input));
+ memset(&output, 0, sizeof(output));
+
+ if (!offset)
+ return false;
+
+ if (!dc->cap_funcs.get_dcc_compression_cap)
+ return false;
+
+ input.format = plane_state->format;
+ input.surface_size.width =
+ plane_state->plane_size.grph.surface_size.width;
+ input.surface_size.height =
+ plane_state->plane_size.grph.surface_size.height;
+ input.swizzle_mode = plane_state->tiling_info.gfx9.swizzle;
+
+ if (plane_state->rotation == ROTATION_ANGLE_0 ||
+ plane_state->rotation == ROTATION_ANGLE_180)
+ input.scan = SCAN_DIRECTION_HORIZONTAL;
+ else if (plane_state->rotation == ROTATION_ANGLE_90 ||
+ plane_state->rotation == ROTATION_ANGLE_270)
+ input.scan = SCAN_DIRECTION_VERTICAL;
+
+ if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
+ return false;
+
+ if (!output.capable)
+ return false;
+
+ if (i64b == 0 && output.grph.rgb.independent_64b_blks != 0)
+ return false;
+
+ plane_state->dcc.enable = 1;
+ plane_state->dcc.grph.meta_pitch =
+ AMDGPU_TILING_GET(info, DCC_PITCH_MAX) + 1;
+ plane_state->dcc.grph.independent_64b_blks = i64b;
+
+ dcc_address = get_dcc_address(afb->address, info);
+ plane_state->address.grph.meta_addr.low_part =
+ lower_32_bits(dcc_address);
+ plane_state->address.grph.meta_addr.high_part =
+ upper_32_bits(dcc_address);
+
+ return true;
+}
+
static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
struct dc_plane_state *plane_state,
const struct amdgpu_framebuffer *amdgpu_fb)
@@ -2336,6 +2414,10 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
return -EINVAL;
}
+ memset(&plane_state->address, 0, sizeof(plane_state->address));
+ memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info));
+ memset(&plane_state->dcc, 0, sizeof(plane_state->dcc));
+
if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
plane_state->address.type = PLN_ADDR_TYPE_GRAPHICS;
plane_state->plane_size.grph.surface_size.x = 0;
@@ -2367,8 +2449,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
plane_state->color_space = COLOR_SPACE_YCBCR709;
}
- memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info));
-
/* Fill GFX8 params */
if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
@@ -2417,6 +2497,9 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
plane_state->tiling_info.gfx9.swizzle =
AMDGPU_TILING_GET(tiling_flags, SWIZZLE_MODE);
plane_state->tiling_info.gfx9.shaderEnable = 1;
+
+ fill_plane_dcc_attributes(adev, amdgpu_fb, plane_state,
+ tiling_flags);
}
plane_state->visible = true;
@@ -2580,7 +2663,7 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing)
* according to HDMI spec, we use YCbCr709 and YCbCr601
* respectively
*/
- if (dc_crtc_timing->pix_clk_khz > 27030) {
+ if (dc_crtc_timing->pix_clk_100hz > 270300) {
if (dc_crtc_timing->flags.Y_ONLY)
color_space =
COLOR_SPACE_YCBCR709_LIMITED;
@@ -2623,7 +2706,7 @@ static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_
if (timing_out->display_color_depth <= COLOR_DEPTH_888)
return;
do {
- normalized_clk = timing_out->pix_clk_khz;
+ normalized_clk = timing_out->pix_clk_100hz / 10;
/* YCbCr 4:2:0 requires additional adjustment of 1/2 */
if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)
normalized_clk /= 2;
@@ -2666,10 +2749,10 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
timing_out->v_border_bottom = 0;
/* TODO: un-hardcode */
if (drm_mode_is_420_only(info, mode_in)
- && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444)
- && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
else
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
@@ -2704,14 +2787,14 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
timing_out->v_sync_width =
mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
- timing_out->pix_clk_khz = mode_in->crtc_clock;
+ timing_out->pix_clk_100hz = mode_in->crtc_clock * 10;
timing_out->aspect_ratio = get_aspect_ratio(mode_in);
stream->output_color_space = get_output_color_space(timing_out);
stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
- if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
adjust_colour_depth_from_display_info(timing_out, info);
}
@@ -2832,7 +2915,7 @@ static void set_master_stream(struct dc_stream_state *stream_set[],
if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
int refresh_rate = 0;
- refresh_rate = (stream_set[j]->timing.pix_clk_khz*1000)/
+ refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/
(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
if (refresh_rate > highest_rfr) {
highest_rfr = refresh_rate;
@@ -2889,11 +2972,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
drm_connector = &aconnector->base;
if (!aconnector->dc_sink) {
- if (!aconnector->mst_port) {
- sink = create_fake_sink(aconnector);
- if (!sink)
- return stream;
- }
+ sink = create_fake_sink(aconnector);
+ if (!sink)
+ return stream;
} else {
sink = aconnector->dc_sink;
}
@@ -2905,6 +2986,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
goto finish;
}
+ stream->dm_stream_context = aconnector;
+
list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
/* Search for preferred mode */
if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
@@ -2956,10 +3039,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
drm_connector,
sink);
- update_stream_signal(stream);
-
- if (dm_state && dm_state->freesync_capable)
- stream->ignore_msa_timing_param = true;
+ update_stream_signal(stream, sink);
finish:
if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON)
@@ -3532,6 +3612,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
struct amdgpu_bo *rbo;
uint64_t chroma_addr = 0;
struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
+ uint64_t tiling_flags, dcc_address;
unsigned int awidth;
uint32_t domain;
int r;
@@ -3572,6 +3653,9 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
DRM_ERROR("%p bind failed\n", rbo);
return r;
}
+
+ amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
+
amdgpu_bo_unreserve(rbo);
afb->address = amdgpu_bo_gpu_offset(rbo);
@@ -3585,6 +3669,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
plane_state->address.grph.addr.low_part = lower_32_bits(afb->address);
plane_state->address.grph.addr.high_part = upper_32_bits(afb->address);
+
+ dcc_address =
+ get_dcc_address(afb->address, tiling_flags);
+ plane_state->address.grph.meta_addr.low_part =
+ lower_32_bits(dcc_address);
+ plane_state->address.grph.meta_addr.high_part =
+ upper_32_bits(dcc_address);
} else {
awidth = ALIGN(new_state->fb->width, 64);
plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
@@ -4070,7 +4161,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
}
if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+ connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP) {
drm_connector_attach_vrr_capable_property(
&aconnector->base);
}
@@ -4456,20 +4548,6 @@ static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
acrtc->crtc_id);
}
-struct dc_stream_status *dc_state_get_stream_status(
- struct dc_state *state,
- struct dc_stream_state *stream)
-{
- uint8_t i;
-
- for (i = 0; i < state->stream_count; i++) {
- if (stream == state->streams[i])
- return &state->stream_status[i];
- }
-
- return NULL;
-}
-
static void update_freesync_state_on_stream(
struct amdgpu_display_manager *dm,
struct dm_crtc_state *new_crtc_state,
@@ -4523,12 +4601,12 @@ static void update_freesync_state_on_stream(
TRANSFER_FUNC_UNKNOWN,
&vrr_infopacket);
- new_crtc_state->freesync_timing_changed =
+ new_crtc_state->freesync_timing_changed |=
(memcmp(&new_crtc_state->vrr_params.adjust,
&vrr_params.adjust,
sizeof(vrr_params.adjust)) != 0);
- new_crtc_state->freesync_vrr_info_changed =
+ new_crtc_state->freesync_vrr_info_changed |=
(memcmp(&new_crtc_state->vrr_infopacket,
&vrr_infopacket,
sizeof(vrr_infopacket)) != 0);
@@ -4544,254 +4622,6 @@ static void update_freesync_state_on_stream(
new_crtc_state->base.crtc->base.id,
(int)new_crtc_state->base.vrr_enabled,
(int)vrr_params.state);
-
- if (new_crtc_state->freesync_timing_changed)
- DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n",
- new_crtc_state->base.crtc->base.id,
- vrr_params.adjust.v_total_min,
- vrr_params.adjust.v_total_max);
-}
-
-/*
- * Executes flip
- *
- * Waits on all BO's fences and for proper vblank count
- */
-static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- uint32_t target,
- struct dc_state *state)
-{
- unsigned long flags;
- uint64_t timestamp_ns;
- uint32_t target_vblank;
- int r, vpos, hpos;
- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
- struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
- struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]);
- struct amdgpu_device *adev = crtc->dev->dev_private;
- bool async_flip = (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
- struct dc_flip_addrs addr = { {0} };
- /* TODO eliminate or rename surface_update */
- struct dc_surface_update surface_updates[1] = { {0} };
- struct dc_stream_update stream_update = {0};
- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
- struct dc_stream_status *stream_status;
- struct dc_plane_state *surface;
-
-
- /* Prepare wait for target vblank early - before the fence-waits */
- target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
- amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id);
-
- /*
- * TODO This might fail and hence better not used, wait
- * explicitly on fences instead
- * and in general should be called for
- * blocking commit to as per framework helpers
- */
- r = amdgpu_bo_reserve(abo, true);
- if (unlikely(r != 0)) {
- DRM_ERROR("failed to reserve buffer before flip\n");
- WARN_ON(1);
- }
-
- /* Wait for all fences on this FB */
- WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
- MAX_SCHEDULE_TIMEOUT) < 0);
-
- amdgpu_bo_unreserve(abo);
-
- /*
- * Wait until we're out of the vertical blank period before the one
- * targeted by the flip
- */
- while ((acrtc->enabled &&
- (amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id,
- 0, &vpos, &hpos, NULL,
- NULL, &crtc->hwmode)
- & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
- (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
- (int)(target_vblank -
- amdgpu_get_vblank_counter_kms(adev->ddev, acrtc->crtc_id)) > 0)) {
- usleep_range(1000, 1100);
- }
-
- /* Flip */
- spin_lock_irqsave(&crtc->dev->event_lock, flags);
-
- WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
- WARN_ON(!acrtc_state->stream);
-
- addr.address.grph.addr.low_part = lower_32_bits(afb->address);
- addr.address.grph.addr.high_part = upper_32_bits(afb->address);
- addr.flip_immediate = async_flip;
-
- timestamp_ns = ktime_get_ns();
- addr.flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
-
-
- if (acrtc->base.state->event)
- prepare_flip_isr(acrtc);
-
- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-
- stream_status = dc_stream_get_status(acrtc_state->stream);
- if (!stream_status) {
- DRM_ERROR("No stream status for CRTC: id=%d\n",
- acrtc->crtc_id);
- return;
- }
-
- surface = stream_status->plane_states[0];
- surface_updates->surface = surface;
-
- if (!surface) {
- DRM_ERROR("No surface for CRTC: id=%d\n",
- acrtc->crtc_id);
- return;
- }
- surface_updates->flip_addr = &addr;
-
- if (acrtc_state->stream) {
- update_freesync_state_on_stream(
- &adev->dm,
- acrtc_state,
- acrtc_state->stream,
- surface,
- addr.flip_timestamp_in_us);
-
- if (acrtc_state->freesync_timing_changed)
- stream_update.adjust =
- &acrtc_state->stream->adjust;
-
- if (acrtc_state->freesync_vrr_info_changed)
- stream_update.vrr_infopacket =
- &acrtc_state->stream->vrr_infopacket;
- }
-
- /* Update surface timing information. */
- surface->time.time_elapsed_in_us[surface->time.index] =
- addr.flip_timestamp_in_us - surface->time.prev_update_time_in_us;
- surface->time.prev_update_time_in_us = addr.flip_timestamp_in_us;
- surface->time.index++;
- if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
- surface->time.index = 0;
-
- mutex_lock(&adev->dm.dc_lock);
-
- dc_commit_updates_for_stream(adev->dm.dc,
- surface_updates,
- 1,
- acrtc_state->stream,
- &stream_update,
- &surface_updates->surface,
- state);
- mutex_unlock(&adev->dm.dc_lock);
-
- DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
- __func__,
- addr.address.grph.addr.high_part,
- addr.address.grph.addr.low_part);
-}
-
-/*
- * TODO this whole function needs to go
- *
- * dc_surface_update is needlessly complex. See if we can just replace this
- * with a dc_plane_state and follow the atomic model a bit more closely here.
- */
-static bool commit_planes_to_stream(
- struct amdgpu_display_manager *dm,
- struct dc *dc,
- struct dc_plane_state **plane_states,
- uint8_t new_plane_count,
- struct dm_crtc_state *dm_new_crtc_state,
- struct dm_crtc_state *dm_old_crtc_state,
- struct dc_state *state)
-{
- /* no need to dynamically allocate this. it's pretty small */
- struct dc_surface_update updates[MAX_SURFACES];
- struct dc_flip_addrs *flip_addr;
- struct dc_plane_info *plane_info;
- struct dc_scaling_info *scaling_info;
- int i;
- struct dc_stream_state *dc_stream = dm_new_crtc_state->stream;
- struct dc_stream_update *stream_update =
- kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
- unsigned int abm_level;
-
- if (!stream_update) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- flip_addr = kcalloc(MAX_SURFACES, sizeof(struct dc_flip_addrs),
- GFP_KERNEL);
- plane_info = kcalloc(MAX_SURFACES, sizeof(struct dc_plane_info),
- GFP_KERNEL);
- scaling_info = kcalloc(MAX_SURFACES, sizeof(struct dc_scaling_info),
- GFP_KERNEL);
-
- if (!flip_addr || !plane_info || !scaling_info) {
- kfree(flip_addr);
- kfree(plane_info);
- kfree(scaling_info);
- kfree(stream_update);
- return false;
- }
-
- memset(updates, 0, sizeof(updates));
-
- stream_update->src = dc_stream->src;
- stream_update->dst = dc_stream->dst;
- stream_update->out_transfer_func = dc_stream->out_transfer_func;
-
- if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
- abm_level = dm_new_crtc_state->abm_level;
- stream_update->abm_level = &abm_level;
- }
-
- for (i = 0; i < new_plane_count; i++) {
- updates[i].surface = plane_states[i];
- updates[i].gamma =
- (struct dc_gamma *)plane_states[i]->gamma_correction;
- updates[i].in_transfer_func = plane_states[i]->in_transfer_func;
- flip_addr[i].address = plane_states[i]->address;
- flip_addr[i].flip_immediate = plane_states[i]->flip_immediate;
- plane_info[i].color_space = plane_states[i]->color_space;
- plane_info[i].format = plane_states[i]->format;
- plane_info[i].plane_size = plane_states[i]->plane_size;
- plane_info[i].rotation = plane_states[i]->rotation;
- plane_info[i].horizontal_mirror = plane_states[i]->horizontal_mirror;
- plane_info[i].stereo_format = plane_states[i]->stereo_format;
- plane_info[i].tiling_info = plane_states[i]->tiling_info;
- plane_info[i].visible = plane_states[i]->visible;
- plane_info[i].per_pixel_alpha = plane_states[i]->per_pixel_alpha;
- plane_info[i].dcc = plane_states[i]->dcc;
- scaling_info[i].scaling_quality = plane_states[i]->scaling_quality;
- scaling_info[i].src_rect = plane_states[i]->src_rect;
- scaling_info[i].dst_rect = plane_states[i]->dst_rect;
- scaling_info[i].clip_rect = plane_states[i]->clip_rect;
-
- updates[i].flip_addr = &flip_addr[i];
- updates[i].plane_info = &plane_info[i];
- updates[i].scaling_info = &scaling_info[i];
- }
-
- mutex_lock(&dm->dc_lock);
- dc_commit_updates_for_stream(
- dc,
- updates,
- new_plane_count,
- dc_stream, stream_update, plane_states, state);
- mutex_unlock(&dm->dc_lock);
-
- kfree(flip_addr);
- kfree(plane_info);
- kfree(scaling_info);
- kfree(stream_update);
- return true;
}
static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
@@ -4801,26 +4631,51 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
struct drm_crtc *pcrtc,
bool *wait_for_vblank)
{
- uint32_t i;
+ uint32_t i, r;
+ uint64_t timestamp_ns;
struct drm_plane *plane;
struct drm_plane_state *old_plane_state, *new_plane_state;
- struct dc_stream_state *dc_stream_attach;
- struct dc_plane_state *plane_states_constructed[MAX_SURFACES];
struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
struct drm_crtc_state *new_pcrtc_state =
drm_atomic_get_new_crtc_state(state, pcrtc);
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
struct dm_crtc_state *dm_old_crtc_state =
to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
- int planes_count = 0;
+ int flip_count = 0, planes_count = 0, vpos, hpos;
unsigned long flags;
+ struct amdgpu_bo *abo;
+ uint64_t tiling_flags, dcc_address;
+ uint32_t target, target_vblank;
+
+ struct {
+ struct dc_surface_update surface_updates[MAX_SURFACES];
+ struct dc_flip_addrs flip_addrs[MAX_SURFACES];
+ struct dc_stream_update stream_update;
+ } *flip;
+
+ struct {
+ struct dc_surface_update surface_updates[MAX_SURFACES];
+ struct dc_plane_info plane_infos[MAX_SURFACES];
+ struct dc_scaling_info scaling_infos[MAX_SURFACES];
+ struct dc_stream_update stream_update;
+ } *full;
+
+ flip = kzalloc(sizeof(*flip), GFP_KERNEL);
+ full = kzalloc(sizeof(*full), GFP_KERNEL);
+
+ if (!flip || !full) {
+ dm_error("Failed to allocate update bundles\n");
+ goto cleanup;
+ }
/* update planes when needed */
for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
struct drm_crtc *crtc = new_plane_state->crtc;
struct drm_crtc_state *new_crtc_state;
struct drm_framebuffer *fb = new_plane_state->fb;
+ struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
bool pflip_needed;
+ struct dc_plane_state *dc_plane;
struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
if (plane->type == DRM_PLANE_TYPE_CURSOR) {
@@ -4835,73 +4690,193 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (!new_crtc_state->active)
continue;
- pflip_needed = !state->allow_modeset;
+ pflip_needed = old_plane_state->fb &&
+ old_plane_state->fb != new_plane_state->fb;
- spin_lock_irqsave(&crtc->dev->event_lock, flags);
- if (acrtc_attach->pflip_status != AMDGPU_FLIP_NONE) {
- DRM_ERROR("%s: acrtc %d, already busy\n",
- __func__,
- acrtc_attach->crtc_id);
- /* In commit tail framework this cannot happen */
- WARN_ON(1);
- }
- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-
- if (!pflip_needed || plane->type == DRM_PLANE_TYPE_OVERLAY) {
- WARN_ON(!dm_new_plane_state->dc_state);
-
- plane_states_constructed[planes_count] = dm_new_plane_state->dc_state;
+ dc_plane = dm_new_plane_state->dc_state;
- dc_stream_attach = acrtc_state->stream;
- planes_count++;
-
- } else if (new_crtc_state->planes_changed) {
- /* Assume even ONE crtc with immediate flip means
+ if (pflip_needed) {
+ /*
+ * Assume even ONE crtc with immediate flip means
* entire can't wait for VBLANK
* TODO Check if it's correct
*/
- *wait_for_vblank =
- new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC ?
- false : true;
-
- /* TODO: Needs rework for multiplane flip */
- if (plane->type == DRM_PLANE_TYPE_PRIMARY)
- drm_crtc_vblank_get(crtc);
-
- amdgpu_dm_do_flip(
- crtc,
- fb,
- (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
- dc_state);
+ if (new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC)
+ *wait_for_vblank = false;
+
+ /*
+ * TODO This might fail and hence better not used, wait
+ * explicitly on fences instead
+ * and in general should be called for
+ * blocking commit to as per framework helpers
+ */
+ abo = gem_to_amdgpu_bo(fb->obj[0]);
+ r = amdgpu_bo_reserve(abo, true);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to reserve buffer before flip\n");
+ WARN_ON(1);
+ }
+
+ /* Wait for all fences on this FB */
+ WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
+ MAX_SCHEDULE_TIMEOUT) < 0);
+
+ amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+
+ amdgpu_bo_unreserve(abo);
+
+ flip->flip_addrs[flip_count].address.grph.addr.low_part = lower_32_bits(afb->address);
+ flip->flip_addrs[flip_count].address.grph.addr.high_part = upper_32_bits(afb->address);
+
+ dcc_address = get_dcc_address(afb->address, tiling_flags);
+ flip->flip_addrs[flip_count].address.grph.meta_addr.low_part = lower_32_bits(dcc_address);
+ flip->flip_addrs[flip_count].address.grph.meta_addr.high_part = upper_32_bits(dcc_address);
+
+ flip->flip_addrs[flip_count].flip_immediate =
+ (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
+
+ timestamp_ns = ktime_get_ns();
+ flip->flip_addrs[flip_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
+ flip->surface_updates[flip_count].flip_addr = &flip->flip_addrs[flip_count];
+ flip->surface_updates[flip_count].surface = dc_plane;
+
+ if (!flip->surface_updates[flip_count].surface) {
+ DRM_ERROR("No surface for CRTC: id=%d\n",
+ acrtc_attach->crtc_id);
+ continue;
+ }
+
+ if (plane == pcrtc->primary)
+ update_freesync_state_on_stream(
+ dm,
+ acrtc_state,
+ acrtc_state->stream,
+ dc_plane,
+ flip->flip_addrs[flip_count].flip_timestamp_in_us);
+
+ DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n",
+ __func__,
+ flip->flip_addrs[flip_count].address.grph.addr.high_part,
+ flip->flip_addrs[flip_count].address.grph.addr.low_part);
+
+ flip_count += 1;
}
+ full->surface_updates[planes_count].surface = dc_plane;
+ if (new_pcrtc_state->color_mgmt_changed) {
+ full->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
+ full->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func;
+ }
+
+
+ full->scaling_infos[planes_count].scaling_quality = dc_plane->scaling_quality;
+ full->scaling_infos[planes_count].src_rect = dc_plane->src_rect;
+ full->scaling_infos[planes_count].dst_rect = dc_plane->dst_rect;
+ full->scaling_infos[planes_count].clip_rect = dc_plane->clip_rect;
+ full->surface_updates[planes_count].scaling_info = &full->scaling_infos[planes_count];
+
+
+ full->plane_infos[planes_count].color_space = dc_plane->color_space;
+ full->plane_infos[planes_count].format = dc_plane->format;
+ full->plane_infos[planes_count].plane_size = dc_plane->plane_size;
+ full->plane_infos[planes_count].rotation = dc_plane->rotation;
+ full->plane_infos[planes_count].horizontal_mirror = dc_plane->horizontal_mirror;
+ full->plane_infos[planes_count].stereo_format = dc_plane->stereo_format;
+ full->plane_infos[planes_count].tiling_info = dc_plane->tiling_info;
+ full->plane_infos[planes_count].visible = dc_plane->visible;
+ full->plane_infos[planes_count].per_pixel_alpha = dc_plane->per_pixel_alpha;
+ full->plane_infos[planes_count].dcc = dc_plane->dcc;
+ full->surface_updates[planes_count].plane_info = &full->plane_infos[planes_count];
+
+ planes_count += 1;
+
}
- if (planes_count) {
- unsigned long flags;
+ /*
+ * TODO: For proper atomic behaviour, we should be calling into DC once with
+ * all the changes. However, DC refuses to do pageflips and non-pageflip
+ * changes in the same call. Change DC to respect atomic behaviour,
+ * hopefully eliminating dc_*_update structs in their entirety.
+ */
+ if (flip_count) {
+ target = (uint32_t)drm_crtc_vblank_count(pcrtc) + *wait_for_vblank;
+ /* Prepare wait for target vblank early - before the fence-waits */
+ target_vblank = target - (uint32_t)drm_crtc_vblank_count(pcrtc) +
+ amdgpu_get_vblank_counter_kms(pcrtc->dev, acrtc_attach->crtc_id);
- if (new_pcrtc_state->event) {
+ /*
+ * Wait until we're out of the vertical blank period before the one
+ * targeted by the flip
+ */
+ while ((acrtc_attach->enabled &&
+ (amdgpu_display_get_crtc_scanoutpos(dm->ddev, acrtc_attach->crtc_id,
+ 0, &vpos, &hpos, NULL,
+ NULL, &pcrtc->hwmode)
+ & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
+ (int)(target_vblank -
+ amdgpu_get_vblank_counter_kms(dm->ddev, acrtc_attach->crtc_id)) > 0)) {
+ usleep_range(1000, 1100);
+ }
+ if (acrtc_attach->base.state->event) {
drm_crtc_vblank_get(pcrtc);
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+
+ WARN_ON(acrtc_attach->pflip_status != AMDGPU_FLIP_NONE);
prepare_flip_isr(acrtc_attach);
+
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
- dc_stream_attach->abm_level = acrtc_state->abm_level;
+ if (acrtc_state->stream) {
- if (false == commit_planes_to_stream(dm,
- dm->dc,
- plane_states_constructed,
- planes_count,
- acrtc_state,
- dm_old_crtc_state,
- dc_state))
- dm_error("%s: Failed to attach plane!\n", __func__);
- } else {
- /*TODO BUG Here should go disable planes on CRTC. */
+ if (acrtc_state->freesync_timing_changed)
+ flip->stream_update.adjust =
+ &acrtc_state->stream->adjust;
+
+ if (acrtc_state->freesync_vrr_info_changed)
+ flip->stream_update.vrr_infopacket =
+ &acrtc_state->stream->vrr_infopacket;
+ }
+
+ mutex_lock(&dm->dc_lock);
+ dc_commit_updates_for_stream(dm->dc,
+ flip->surface_updates,
+ flip_count,
+ acrtc_state->stream,
+ &flip->stream_update,
+ dc_state);
+ mutex_unlock(&dm->dc_lock);
+ }
+
+ if (planes_count) {
+ if (new_pcrtc_state->mode_changed) {
+ full->stream_update.src = acrtc_state->stream->src;
+ full->stream_update.dst = acrtc_state->stream->dst;
+ }
+
+ if (new_pcrtc_state->color_mgmt_changed)
+ full->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func;
+
+ acrtc_state->stream->abm_level = acrtc_state->abm_level;
+ if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
+ full->stream_update.abm_level = &acrtc_state->abm_level;
+
+ mutex_lock(&dm->dc_lock);
+ dc_commit_updates_for_stream(dm->dc,
+ full->surface_updates,
+ planes_count,
+ acrtc_state->stream,
+ &full->stream_update,
+ dc_state);
+ mutex_unlock(&dm->dc_lock);
}
+
+cleanup:
+ kfree(flip);
+ kfree(full);
}
/*
@@ -4915,7 +4890,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_state,
struct dc_stream_state *stream_state)
{
- stream_state->mode_changed = crtc_state->mode_changed;
+ stream_state->mode_changed =
+ crtc_state->mode_changed || crtc_state->active_changed;
}
static int amdgpu_dm_atomic_commit(struct drm_device *dev,
@@ -4936,10 +4912,25 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
*/
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+ struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
- if (drm_atomic_crtc_needs_modeset(new_crtc_state) && dm_old_crtc_state->stream)
+ if (drm_atomic_crtc_needs_modeset(new_crtc_state)
+ && dm_old_crtc_state->stream) {
+ /*
+ * If the stream is removed and CRC capture was
+ * enabled on the CRTC the extra vblank reference
+ * needs to be dropped since CRC capture will be
+ * disabled.
+ */
+ if (!dm_new_crtc_state->stream
+ && dm_new_crtc_state->crc_enabled) {
+ drm_crtc_vblank_put(crtc);
+ dm_new_crtc_state->crc_enabled = false;
+ }
+
manage_dm_interrupts(adev, acrtc, false);
+ }
}
/*
* Add check here for SoC's that support hardware cursor plane, to
@@ -5077,8 +5068,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dc_stream_get_status(dm_new_crtc_state->stream);
if (!status)
- status = dc_state_get_stream_status(dc_state,
- dm_new_crtc_state->stream);
+ status = dc_stream_get_status_from_state(dc_state,
+ dm_new_crtc_state->stream);
if (!status)
DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);
@@ -5087,13 +5078,18 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
}
}
- /* Handle scaling, underscan, and abm changes*/
+ /* Handle connector state changes */
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
+ struct dc_surface_update dummy_updates[MAX_SURFACES];
+ struct dc_stream_update stream_update;
struct dc_stream_status *status = NULL;
+ memset(&dummy_updates, 0, sizeof(dummy_updates));
+ memset(&stream_update, 0, sizeof(stream_update));
+
if (acrtc) {
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
@@ -5103,37 +5099,48 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state))
continue;
-
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- /* Skip anything that is not scaling or underscan changes */
if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) &&
(dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level))
continue;
- update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
- dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
+ if (is_scaling_state_different(dm_new_con_state, dm_old_con_state)) {
+ update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
+ dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
- if (!dm_new_crtc_state->stream)
- continue;
+ stream_update.src = dm_new_crtc_state->stream->src;
+ stream_update.dst = dm_new_crtc_state->stream->dst;
+ }
+
+ if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
+ dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level;
+
+ stream_update.abm_level = &dm_new_crtc_state->abm_level;
+ }
status = dc_stream_get_status(dm_new_crtc_state->stream);
WARN_ON(!status);
WARN_ON(!status->plane_count);
- dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level;
+ /*
+ * TODO: DC refuses to perform stream updates without a dc_surface_update.
+ * Here we create an empty update on each plane.
+ * To fix this, DC should permit updating only stream properties.
+ */
+ for (j = 0; j < status->plane_count; j++)
+ dummy_updates[j].surface = status->plane_states[0];
+
- /*TODO How it works with MPO ?*/
- if (!commit_planes_to_stream(
- dm,
- dm->dc,
- status->plane_states,
- status->plane_count,
- dm_new_crtc_state,
- to_dm_crtc_state(old_crtc_state),
- dc_state))
- dm_error("%s: Failed to update stream scaling!\n", __func__);
+ mutex_lock(&dm->dc_lock);
+ dc_commit_updates_for_stream(dm->dc,
+ dummy_updates,
+ status->plane_count,
+ dm_new_crtc_state->stream,
+ &stream_update,
+ dc_state);
+ mutex_unlock(&dm->dc_lock);
}
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
@@ -5158,6 +5165,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
continue;
manage_dm_interrupts(adev, acrtc, true);
+
+#ifdef CONFIG_DEBUG_FS
+ /* The stream has changed so CRC capture needs to re-enabled. */
+ if (dm_new_crtc_state->crc_enabled)
+ amdgpu_dm_crtc_set_crc_source(crtc, "auto");
+#endif
}
/* update planes when needed per crtc*/
@@ -5184,18 +5197,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
}
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ /* Signal HW programming completion */
+ drm_atomic_helper_commit_hw_done(state);
if (wait_for_vblank)
drm_atomic_helper_wait_for_flip_done(dev, state);
- /*
- * FIXME:
- * Delay hw_done() until flip_done() is signaled. This is to block
- * another commit from freeing the CRTC state while we're still
- * waiting on flip_done.
- */
- drm_atomic_helper_commit_hw_done(state);
-
drm_atomic_helper_cleanup_planes(dev, state);
/*
@@ -5359,10 +5366,13 @@ static void get_freesync_config_for_crtc(
struct mod_freesync_config config = {0};
struct amdgpu_dm_connector *aconnector =
to_amdgpu_dm_connector(new_con_state->base.connector);
+ struct drm_display_mode *mode = &new_crtc_state->base.mode;
- new_crtc_state->vrr_supported = new_con_state->freesync_capable;
+ new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
+ aconnector->min_vfreq <= drm_mode_vrefresh(mode);
- if (new_con_state->freesync_capable) {
+ if (new_crtc_state->vrr_supported) {
+ new_crtc_state->stream->ignore_msa_timing_param = true;
config.state = new_crtc_state->base.vrr_enabled ?
VRR_STATE_ACTIVE_VARIABLE :
VRR_STATE_INACTIVE;
@@ -5388,15 +5398,15 @@ static void reset_freesync_config_for_crtc(
sizeof(new_crtc_state->vrr_infopacket));
}
-static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
- struct drm_atomic_state *state,
- bool enable,
- bool *lock_and_validation_needed)
+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 dm_atomic_state *dm_state = NULL;
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- int i;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
struct dc_stream_state *new_stream;
int ret = 0;
@@ -5405,200 +5415,203 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
* TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set
* update changed items
*/
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
- struct amdgpu_crtc *acrtc = NULL;
- struct amdgpu_dm_connector *aconnector = NULL;
- struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL;
- struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL;
- struct drm_plane_state *new_plane_state = NULL;
+ struct amdgpu_crtc *acrtc = NULL;
+ struct amdgpu_dm_connector *aconnector = NULL;
+ struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL;
+ struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL;
+ struct drm_plane_state *new_plane_state = NULL;
- new_stream = NULL;
+ new_stream = NULL;
- dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
- acrtc = to_amdgpu_crtc(crtc);
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ acrtc = to_amdgpu_crtc(crtc);
- new_plane_state = drm_atomic_get_new_plane_state(state, new_crtc_state->crtc->primary);
+ new_plane_state = drm_atomic_get_new_plane_state(state, new_crtc_state->crtc->primary);
- if (new_crtc_state->enable && new_plane_state && !new_plane_state->fb) {
- ret = -EINVAL;
- goto fail;
- }
+ if (new_crtc_state->enable && new_plane_state && !new_plane_state->fb) {
+ ret = -EINVAL;
+ goto fail;
+ }
- aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
+ aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
- /* TODO This hack should go away */
- if (aconnector && enable) {
- /* Make sure fake sink is created in plug-in scenario */
- drm_new_conn_state = drm_atomic_get_new_connector_state(state,
- &aconnector->base);
- drm_old_conn_state = drm_atomic_get_old_connector_state(state,
- &aconnector->base);
+ /* TODO This hack should go away */
+ if (aconnector && enable) {
+ /* Make sure fake sink is created in plug-in scenario */
+ drm_new_conn_state = drm_atomic_get_new_connector_state(state,
+ &aconnector->base);
+ drm_old_conn_state = drm_atomic_get_old_connector_state(state,
+ &aconnector->base);
- if (IS_ERR(drm_new_conn_state)) {
- ret = PTR_ERR_OR_ZERO(drm_new_conn_state);
- break;
- }
+ if (IS_ERR(drm_new_conn_state)) {
+ ret = PTR_ERR_OR_ZERO(drm_new_conn_state);
+ goto fail;
+ }
- dm_new_conn_state = to_dm_connector_state(drm_new_conn_state);
- dm_old_conn_state = to_dm_connector_state(drm_old_conn_state);
+ dm_new_conn_state = to_dm_connector_state(drm_new_conn_state);
+ dm_old_conn_state = to_dm_connector_state(drm_old_conn_state);
- new_stream = create_stream_for_sink(aconnector,
- &new_crtc_state->mode,
- dm_new_conn_state,
- dm_old_crtc_state->stream);
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ goto skip_modeset;
- /*
- * we can have no stream on ACTION_SET if a display
- * was disconnected during S3, in this case it is not an
- * error, the OS will be updated after detection, and
- * will do the right thing on next atomic commit
- */
+ new_stream = create_stream_for_sink(aconnector,
+ &new_crtc_state->mode,
+ dm_new_conn_state,
+ dm_old_crtc_state->stream);
- if (!new_stream) {
- DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
- __func__, acrtc->base.base.id);
- break;
- }
-
- dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
+ /*
+ * we can have no stream on ACTION_SET if a display
+ * was disconnected during S3, in this case it is not an
+ * error, the OS will be updated after detection, and
+ * will do the right thing on next atomic commit
+ */
- if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
- dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
- new_crtc_state->mode_changed = false;
- DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d",
- new_crtc_state->mode_changed);
- }
+ if (!new_stream) {
+ DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
+ __func__, acrtc->base.base.id);
+ ret = -ENOMEM;
+ goto fail;
}
- if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
- goto next_crtc;
+ dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
- DRM_DEBUG_DRIVER(
- "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
- "planes_changed:%d, mode_changed:%d,active_changed:%d,"
- "connectors_changed:%d\n",
- acrtc->crtc_id,
- new_crtc_state->enable,
- new_crtc_state->active,
- new_crtc_state->planes_changed,
- new_crtc_state->mode_changed,
- new_crtc_state->active_changed,
- new_crtc_state->connectors_changed);
+ if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
+ dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
+ new_crtc_state->mode_changed = false;
+ DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d",
+ new_crtc_state->mode_changed);
+ }
+ }
- /* Remove stream for any changed/disabled CRTC */
- if (!enable) {
+ /* mode_changed flag may get updated above, need to check again */
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ goto skip_modeset;
- if (!dm_old_crtc_state->stream)
- goto next_crtc;
+ DRM_DEBUG_DRIVER(
+ "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
+ "planes_changed:%d, mode_changed:%d,active_changed:%d,"
+ "connectors_changed:%d\n",
+ acrtc->crtc_id,
+ new_crtc_state->enable,
+ new_crtc_state->active,
+ new_crtc_state->planes_changed,
+ new_crtc_state->mode_changed,
+ new_crtc_state->active_changed,
+ new_crtc_state->connectors_changed);
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret)
- goto fail;
+ /* Remove stream for any changed/disabled CRTC */
+ if (!enable) {
- DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n",
- crtc->base.id);
+ if (!dm_old_crtc_state->stream)
+ goto skip_modeset;
- /* i.e. reset mode */
- if (dc_remove_stream_from_ctx(
- dm->dc,
- dm_state->context,
- dm_old_crtc_state->stream) != DC_OK) {
- ret = -EINVAL;
- goto fail;
- }
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret)
+ goto fail;
- dc_stream_release(dm_old_crtc_state->stream);
- dm_new_crtc_state->stream = NULL;
+ DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n",
+ crtc->base.id);
- reset_freesync_config_for_crtc(dm_new_crtc_state);
+ /* i.e. reset mode */
+ if (dc_remove_stream_from_ctx(
+ dm->dc,
+ dm_state->context,
+ dm_old_crtc_state->stream) != DC_OK) {
+ ret = -EINVAL;
+ goto fail;
+ }
- *lock_and_validation_needed = true;
+ dc_stream_release(dm_old_crtc_state->stream);
+ dm_new_crtc_state->stream = NULL;
- } else {/* Add stream for any updated/enabled CRTC */
- /*
- * Quick fix to prevent NULL pointer on new_stream when
- * added MST connectors not found in existing crtc_state in the chained mode
- * TODO: need to dig out the root cause of that
- */
- if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
- goto next_crtc;
+ reset_freesync_config_for_crtc(dm_new_crtc_state);
+
+ *lock_and_validation_needed = true;
- if (modereset_required(new_crtc_state))
- goto next_crtc;
+ } else {/* Add stream for any updated/enabled CRTC */
+ /*
+ * Quick fix to prevent NULL pointer on new_stream when
+ * added MST connectors not found in existing crtc_state in the chained mode
+ * TODO: need to dig out the root cause of that
+ */
+ if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
+ goto skip_modeset;
- if (modeset_required(new_crtc_state, new_stream,
- dm_old_crtc_state->stream)) {
+ if (modereset_required(new_crtc_state))
+ goto skip_modeset;
- WARN_ON(dm_new_crtc_state->stream);
+ if (modeset_required(new_crtc_state, new_stream,
+ dm_old_crtc_state->stream)) {
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret)
- goto fail;
+ WARN_ON(dm_new_crtc_state->stream);
- dm_new_crtc_state->stream = new_stream;
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret)
+ goto fail;
- dc_stream_retain(new_stream);
+ dm_new_crtc_state->stream = new_stream;
- DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
- crtc->base.id);
+ dc_stream_retain(new_stream);
- if (dc_add_stream_to_ctx(
- dm->dc,
- dm_state->context,
- dm_new_crtc_state->stream) != DC_OK) {
- ret = -EINVAL;
- goto fail;
- }
+ DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
+ crtc->base.id);
- *lock_and_validation_needed = true;
+ if (dc_add_stream_to_ctx(
+ dm->dc,
+ dm_state->context,
+ dm_new_crtc_state->stream) != DC_OK) {
+ ret = -EINVAL;
+ goto fail;
}
- }
-next_crtc:
- /* Release extra reference */
- if (new_stream)
- dc_stream_release(new_stream);
+ *lock_and_validation_needed = true;
+ }
+ }
- /*
- * We want to do dc stream updates that do not require a
- * full modeset below.
- */
- if (!(enable && aconnector && new_crtc_state->enable &&
- new_crtc_state->active))
- continue;
- /*
- * Given above conditions, the dc state cannot be NULL because:
- * 1. We're in the process of enabling CRTCs (just been added
- * to the dc context, or already is on the context)
- * 2. Has a valid connector attached, and
- * 3. Is currently active and enabled.
- * => The dc stream state currently exists.
- */
- BUG_ON(dm_new_crtc_state->stream == NULL);
+skip_modeset:
+ /* Release extra reference */
+ if (new_stream)
+ dc_stream_release(new_stream);
- /* Scaling or underscan settings */
- if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state))
- update_stream_scaling_settings(
- &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
+ /*
+ * We want to do dc stream updates that do not require a
+ * full modeset below.
+ */
+ if (!(enable && aconnector && new_crtc_state->enable &&
+ new_crtc_state->active))
+ return 0;
+ /*
+ * Given above conditions, the dc state cannot be NULL because:
+ * 1. We're in the process of enabling CRTCs (just been added
+ * to the dc context, or already is on the context)
+ * 2. Has a valid connector attached, and
+ * 3. Is currently active and enabled.
+ * => The dc stream state currently exists.
+ */
+ BUG_ON(dm_new_crtc_state->stream == NULL);
- /*
- * Color management settings. We also update color properties
- * when a modeset is needed, to ensure it gets reprogrammed.
- */
- if (dm_new_crtc_state->base.color_mgmt_changed ||
- drm_atomic_crtc_needs_modeset(new_crtc_state)) {
- ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state);
- if (ret)
- goto fail;
- amdgpu_dm_set_ctm(dm_new_crtc_state);
- }
+ /* Scaling or underscan settings */
+ if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state))
+ update_stream_scaling_settings(
+ &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
- /* Update Freesync settings. */
- get_freesync_config_for_crtc(dm_new_crtc_state,
- dm_new_conn_state);
+ /*
+ * Color management settings. We also update color properties
+ * when a modeset is needed, to ensure it gets reprogrammed.
+ */
+ if (dm_new_crtc_state->base.color_mgmt_changed ||
+ drm_atomic_crtc_needs_modeset(new_crtc_state)) {
+ ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state);
+ if (ret)
+ goto fail;
+ amdgpu_dm_set_ctm(dm_new_crtc_state);
}
+ /* Update Freesync settings. */
+ get_freesync_config_for_crtc(dm_new_crtc_state,
+ dm_new_conn_state);
+
return ret;
fail:
@@ -5607,145 +5620,141 @@ fail:
return ret;
}
-static int dm_update_planes_state(struct dc *dc,
- struct drm_atomic_state *state,
- bool enable,
- bool *lock_and_validation_needed)
+static int dm_update_plane_state(struct dc *dc,
+ struct drm_atomic_state *state,
+ struct drm_plane *plane,
+ struct drm_plane_state *old_plane_state,
+ struct drm_plane_state *new_plane_state,
+ bool enable,
+ bool *lock_and_validation_needed)
{
struct dm_atomic_state *dm_state = NULL;
struct drm_crtc *new_plane_crtc, *old_plane_crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- struct drm_plane *plane;
- struct drm_plane_state *old_plane_state, *new_plane_state;
struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
- int i ;
/* TODO return page_flip_needed() function */
bool pflip_needed = !state->allow_modeset;
int ret = 0;
- /* Add new planes, in reverse order as DC expectation */
- for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
- new_plane_crtc = new_plane_state->crtc;
- old_plane_crtc = old_plane_state->crtc;
- dm_new_plane_state = to_dm_plane_state(new_plane_state);
- dm_old_plane_state = to_dm_plane_state(old_plane_state);
+ new_plane_crtc = new_plane_state->crtc;
+ old_plane_crtc = old_plane_state->crtc;
+ dm_new_plane_state = to_dm_plane_state(new_plane_state);
+ dm_old_plane_state = to_dm_plane_state(old_plane_state);
- /*TODO Implement atomic check for cursor plane */
- if (plane->type == DRM_PLANE_TYPE_CURSOR)
- continue;
+ /*TODO Implement atomic check for cursor plane */
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ return 0;
- /* Remove any changed/removed planes */
- if (!enable) {
- if (pflip_needed &&
- plane->type != DRM_PLANE_TYPE_OVERLAY)
- continue;
+ /* Remove any changed/removed planes */
+ if (!enable) {
+ if (pflip_needed &&
+ plane->type != DRM_PLANE_TYPE_OVERLAY)
+ return 0;
- if (!old_plane_crtc)
- continue;
+ if (!old_plane_crtc)
+ return 0;
- old_crtc_state = drm_atomic_get_old_crtc_state(
- state, old_plane_crtc);
- dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+ old_crtc_state = drm_atomic_get_old_crtc_state(
+ state, old_plane_crtc);
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- if (!dm_old_crtc_state->stream)
- continue;
+ if (!dm_old_crtc_state->stream)
+ return 0;
- DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n",
- plane->base.id, old_plane_crtc->base.id);
+ DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n",
+ plane->base.id, old_plane_crtc->base.id);
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret)
- return ret;
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret)
+ return ret;
- if (!dc_remove_plane_from_context(
- dc,
- dm_old_crtc_state->stream,
- dm_old_plane_state->dc_state,
- dm_state->context)) {
+ if (!dc_remove_plane_from_context(
+ dc,
+ dm_old_crtc_state->stream,
+ dm_old_plane_state->dc_state,
+ dm_state->context)) {
- ret = EINVAL;
- return ret;
- }
+ ret = EINVAL;
+ return ret;
+ }
- dc_plane_state_release(dm_old_plane_state->dc_state);
- dm_new_plane_state->dc_state = NULL;
+ dc_plane_state_release(dm_old_plane_state->dc_state);
+ dm_new_plane_state->dc_state = NULL;
- *lock_and_validation_needed = true;
+ *lock_and_validation_needed = true;
- } else { /* Add new planes */
- struct dc_plane_state *dc_new_plane_state;
+ } else { /* Add new planes */
+ struct dc_plane_state *dc_new_plane_state;
- if (drm_atomic_plane_disabling(plane->state, new_plane_state))
- continue;
+ if (drm_atomic_plane_disabling(plane->state, new_plane_state))
+ return 0;
- if (!new_plane_crtc)
- continue;
+ if (!new_plane_crtc)
+ return 0;
- new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
- dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
- if (!dm_new_crtc_state->stream)
- continue;
+ if (!dm_new_crtc_state->stream)
+ return 0;
- if (pflip_needed &&
- plane->type != DRM_PLANE_TYPE_OVERLAY)
- continue;
+ if (pflip_needed && plane->type != DRM_PLANE_TYPE_OVERLAY)
+ return 0;
- WARN_ON(dm_new_plane_state->dc_state);
+ WARN_ON(dm_new_plane_state->dc_state);
- dc_new_plane_state = dc_create_plane_state(dc);
- if (!dc_new_plane_state)
- return -ENOMEM;
+ dc_new_plane_state = dc_create_plane_state(dc);
+ if (!dc_new_plane_state)
+ return -ENOMEM;
- DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
- plane->base.id, new_plane_crtc->base.id);
+ DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
+ plane->base.id, new_plane_crtc->base.id);
- ret = fill_plane_attributes(
- new_plane_crtc->dev->dev_private,
- dc_new_plane_state,
- new_plane_state,
- new_crtc_state);
- if (ret) {
- dc_plane_state_release(dc_new_plane_state);
- return ret;
- }
+ ret = fill_plane_attributes(
+ new_plane_crtc->dev->dev_private,
+ dc_new_plane_state,
+ new_plane_state,
+ new_crtc_state);
+ if (ret) {
+ dc_plane_state_release(dc_new_plane_state);
+ return ret;
+ }
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret) {
- dc_plane_state_release(dc_new_plane_state);
- return ret;
- }
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret) {
+ dc_plane_state_release(dc_new_plane_state);
+ return ret;
+ }
- /*
- * Any atomic check errors that occur after this will
- * not need a release. The plane state will be attached
- * to the stream, and therefore part of the atomic
- * state. It'll be released when the atomic state is
- * cleaned.
- */
- if (!dc_add_plane_to_context(
- dc,
- dm_new_crtc_state->stream,
- dc_new_plane_state,
- dm_state->context)) {
-
- dc_plane_state_release(dc_new_plane_state);
- return -EINVAL;
- }
+ /*
+ * Any atomic check errors that occur after this will
+ * not need a release. The plane state will be attached
+ * to the stream, and therefore part of the atomic
+ * state. It'll be released when the atomic state is
+ * cleaned.
+ */
+ if (!dc_add_plane_to_context(
+ dc,
+ dm_new_crtc_state->stream,
+ dc_new_plane_state,
+ dm_state->context)) {
- dm_new_plane_state->dc_state = dc_new_plane_state;
+ dc_plane_state_release(dc_new_plane_state);
+ return -EINVAL;
+ }
- /* Tell DC to do a full surface update every time there
- * is a plane change. Inefficient, but works for now.
- */
- dm_new_plane_state->dc_state->update_flags.bits.full_update = 1;
+ dm_new_plane_state->dc_state = dc_new_plane_state;
- *lock_and_validation_needed = true;
- }
+ /* Tell DC to do a full surface update every time there
+ * is a plane change. Inefficient, but works for now.
+ */
+ dm_new_plane_state->dc_state->update_flags.bits.full_update = 1;
+
+ *lock_and_validation_needed = true;
}
@@ -5769,11 +5778,13 @@ dm_determine_update_type_for_commit(struct dc *dc,
struct dm_crtc_state *new_dm_crtc_state, *old_dm_crtc_state;
struct dc_stream_status *status = NULL;
- struct dc_surface_update *updates = kzalloc(MAX_SURFACES * sizeof(struct dc_surface_update), GFP_KERNEL);
- struct dc_plane_state *surface = kzalloc(MAX_SURFACES * sizeof(struct dc_plane_state), GFP_KERNEL);
- struct dc_stream_update stream_update;
+ struct dc_surface_update *updates;
+ struct dc_plane_state *surface;
enum surface_update_type update_type = UPDATE_TYPE_FAST;
+ updates = kcalloc(MAX_SURFACES, sizeof(*updates), GFP_KERNEL);
+ surface = kcalloc(MAX_SURFACES, sizeof(*surface), GFP_KERNEL);
+
if (!updates || !surface) {
DRM_ERROR("Plane or surface update failed to allocate");
/* Set type to FULL to avoid crashing in DC*/
@@ -5782,79 +5793,85 @@ dm_determine_update_type_for_commit(struct dc *dc,
}
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ struct dc_stream_update stream_update = { 0 };
+
new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
old_dm_crtc_state = to_dm_crtc_state(old_crtc_state);
num_plane = 0;
- if (new_dm_crtc_state->stream) {
-
- for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) {
- new_plane_crtc = new_plane_state->crtc;
- old_plane_crtc = old_plane_state->crtc;
- new_dm_plane_state = to_dm_plane_state(new_plane_state);
- old_dm_plane_state = to_dm_plane_state(old_plane_state);
-
- if (plane->type == DRM_PLANE_TYPE_CURSOR)
- continue;
-
- if (!state->allow_modeset)
- continue;
-
- if (crtc == new_plane_crtc) {
- updates[num_plane].surface = &surface[num_plane];
-
- if (new_crtc_state->mode_changed) {
- updates[num_plane].surface->src_rect =
- new_dm_plane_state->dc_state->src_rect;
- updates[num_plane].surface->dst_rect =
- new_dm_plane_state->dc_state->dst_rect;
- updates[num_plane].surface->rotation =
- new_dm_plane_state->dc_state->rotation;
- updates[num_plane].surface->in_transfer_func =
- new_dm_plane_state->dc_state->in_transfer_func;
- stream_update.dst = new_dm_crtc_state->stream->dst;
- stream_update.src = new_dm_crtc_state->stream->src;
- }
-
- if (new_crtc_state->color_mgmt_changed) {
- updates[num_plane].gamma =
- new_dm_plane_state->dc_state->gamma_correction;
- updates[num_plane].in_transfer_func =
- new_dm_plane_state->dc_state->in_transfer_func;
- stream_update.gamut_remap =
- &new_dm_crtc_state->stream->gamut_remap_matrix;
- stream_update.out_transfer_func =
- new_dm_crtc_state->stream->out_transfer_func;
- }
-
- num_plane++;
- }
+ if (!new_dm_crtc_state->stream) {
+ if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) {
+ update_type = UPDATE_TYPE_FULL;
+ goto cleanup;
}
- if (num_plane > 0) {
- ret = dm_atomic_get_state(state, &dm_state);
- if (ret)
- goto cleanup;
+ continue;
+ }
- old_dm_state = dm_atomic_get_old_state(state);
- if (!old_dm_state) {
- ret = -EINVAL;
- goto cleanup;
- }
+ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) {
+ new_plane_crtc = new_plane_state->crtc;
+ old_plane_crtc = old_plane_state->crtc;
+ new_dm_plane_state = to_dm_plane_state(new_plane_state);
+ old_dm_plane_state = to_dm_plane_state(old_plane_state);
- status = dc_state_get_stream_status(old_dm_state->context,
- new_dm_crtc_state->stream);
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ continue;
- update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane,
- &stream_update, status);
+ if (!state->allow_modeset)
+ continue;
- if (update_type > UPDATE_TYPE_MED) {
- update_type = UPDATE_TYPE_FULL;
- goto cleanup;
- }
+ if (crtc != new_plane_crtc)
+ continue;
+
+ updates[num_plane].surface = &surface[num_plane];
+
+ if (new_crtc_state->mode_changed) {
+ updates[num_plane].surface->src_rect =
+ new_dm_plane_state->dc_state->src_rect;
+ updates[num_plane].surface->dst_rect =
+ new_dm_plane_state->dc_state->dst_rect;
+ updates[num_plane].surface->rotation =
+ new_dm_plane_state->dc_state->rotation;
+ updates[num_plane].surface->in_transfer_func =
+ new_dm_plane_state->dc_state->in_transfer_func;
+ stream_update.dst = new_dm_crtc_state->stream->dst;
+ stream_update.src = new_dm_crtc_state->stream->src;
+ }
+
+ if (new_crtc_state->color_mgmt_changed) {
+ updates[num_plane].gamma =
+ new_dm_plane_state->dc_state->gamma_correction;
+ updates[num_plane].in_transfer_func =
+ new_dm_plane_state->dc_state->in_transfer_func;
+ stream_update.gamut_remap =
+ &new_dm_crtc_state->stream->gamut_remap_matrix;
+ stream_update.out_transfer_func =
+ new_dm_crtc_state->stream->out_transfer_func;
}
- } else if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) {
+ num_plane++;
+ }
+
+ if (num_plane == 0)
+ continue;
+
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret)
+ goto cleanup;
+
+ old_dm_state = dm_atomic_get_old_state(state);
+ if (!old_dm_state) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ status = dc_stream_get_status_from_state(old_dm_state->context,
+ new_dm_crtc_state->stream);
+
+ update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane,
+ &stream_update, status);
+
+ if (update_type > UPDATE_TYPE_MED) {
update_type = UPDATE_TYPE_FULL;
goto cleanup;
}
@@ -5903,6 +5920,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_connector_state *old_con_state, *new_con_state;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
enum surface_update_type update_type = UPDATE_TYPE_FAST;
enum surface_update_type overall_update_type = UPDATE_TYPE_FAST;
@@ -5921,7 +5940,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
!new_crtc_state->color_mgmt_changed &&
- !new_crtc_state->vrr_enabled)
+ old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled)
continue;
if (!new_crtc_state->enable)
@@ -5937,27 +5956,47 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
}
/* Remove exiting planes if they are modified */
- ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed);
- if (ret) {
- goto fail;
+ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
+ ret = dm_update_plane_state(dc, state, plane,
+ old_plane_state,
+ new_plane_state,
+ false,
+ &lock_and_validation_needed);
+ if (ret)
+ goto fail;
}
/* Disable all crtcs which require disable */
- ret = dm_update_crtcs_state(&adev->dm, state, false, &lock_and_validation_needed);
- if (ret) {
- goto fail;
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ ret = dm_update_crtc_state(&adev->dm, state, crtc,
+ old_crtc_state,
+ new_crtc_state,
+ false,
+ &lock_and_validation_needed);
+ if (ret)
+ goto fail;
}
/* Enable all crtcs which require enable */
- ret = dm_update_crtcs_state(&adev->dm, state, true, &lock_and_validation_needed);
- if (ret) {
- goto fail;
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ ret = dm_update_crtc_state(&adev->dm, state, crtc,
+ old_crtc_state,
+ new_crtc_state,
+ true,
+ &lock_and_validation_needed);
+ if (ret)
+ goto fail;
}
/* Add new/modified planes */
- ret = dm_update_planes_state(dc, state, true, &lock_and_validation_needed);
- if (ret) {
- goto fail;
+ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
+ ret = dm_update_plane_state(dc, state, plane,
+ old_plane_state,
+ new_plane_state,
+ true,
+ &lock_and_validation_needed);
+ if (ret)
+ goto fail;
}
/* Run this here since we want to validate the streams we created */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index f088ac585978..a10e3a50d9ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -64,8 +64,10 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
{
+ struct amdgpu_device *adev = crtc->dev->dev_private;
struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
struct dc_stream_state *stream_state = crtc_state->stream;
+ bool enable;
enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
@@ -80,29 +82,33 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
return -EINVAL;
}
- /* When enabling CRC, we should also disable dithering. */
- if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) {
- if (dc_stream_configure_crc(stream_state->ctx->dc,
- stream_state,
- true, true)) {
- crtc_state->crc_enabled = true;
- dc_stream_set_dither_option(stream_state,
- DITHER_OPTION_TRUN8);
- }
- else
- return -EINVAL;
- } else {
- if (dc_stream_configure_crc(stream_state->ctx->dc,
- stream_state,
- false, false)) {
- crtc_state->crc_enabled = false;
- dc_stream_set_dither_option(stream_state,
- DITHER_OPTION_DEFAULT);
- }
- else
- return -EINVAL;
+ enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
+
+ mutex_lock(&adev->dm.dc_lock);
+ if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
+ enable, enable)) {
+ mutex_unlock(&adev->dm.dc_lock);
+ return -EINVAL;
}
+ /* When enabling CRC, we should also disable dithering. */
+ dc_stream_set_dither_option(stream_state,
+ enable ? DITHER_OPTION_TRUN8
+ : DITHER_OPTION_DEFAULT);
+
+ mutex_unlock(&adev->dm.dc_lock);
+
+ /*
+ * Reading the CRC requires the vblank interrupt handler to be
+ * enabled. Keep a reference until CRC capture stops.
+ */
+ if (!crtc_state->crc_enabled && enable)
+ drm_crtc_vblank_get(crtc);
+ else if (crtc_state->crc_enabled && !enable)
+ drm_crtc_vblank_put(crtc);
+
+ crtc_state->crc_enabled = enable;
+
/* Reset crc_skipped on dm state */
crtc_state->crc_skip_count = 0;
return 0;
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 9a7ac58eb18e..4a55cde027cf 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
@@ -671,6 +671,25 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us
return bytes_from_user;
}
+/*
+ * Returns the min and max vrr vfreq through the connector's debugfs file.
+ * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range
+ */
+static int vrr_range_show(struct seq_file *m, void *data)
+{
+ struct drm_connector *connector = m->private;
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
+ if (connector->status != connector_status_connected)
+ return -ENODEV;
+
+ seq_printf(m, "Min: %u\n", (unsigned int)aconnector->min_vfreq);
+ seq_printf(m, "Max: %u\n", (unsigned int)aconnector->max_vfreq);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(vrr_range);
+
static const struct file_operations dp_link_settings_debugfs_fops = {
.owner = THIS_MODULE,
.read = dp_link_settings_read,
@@ -697,7 +716,8 @@ static const struct {
} dp_debugfs_entries[] = {
{"link_settings", &dp_link_settings_debugfs_fops},
{"phy_settings", &dp_phy_settings_debugfs_fop},
- {"test_pattern", &dp_phy_test_pattern_fops}
+ {"test_pattern", &dp_phy_test_pattern_fops},
+ {"vrr_range", &vrr_range_fops}
};
int connector_debugfs_init(struct amdgpu_dm_connector *connector)
@@ -783,6 +803,45 @@ static ssize_t dtn_log_write(
return size;
}
+/*
+ * Backlight at this moment. Read only.
+ * As written to display, taking ABM and backlight lut into account.
+ * Ranges from 0x0 to 0x10000 (= 100% PWM)
+ */
+static int current_backlight_read(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct dc *dc = adev->dm.dc;
+ unsigned int backlight = dc_get_current_backlight_pwm(dc);
+
+ seq_printf(m, "0x%x\n", backlight);
+ return 0;
+}
+
+/*
+ * Backlight value that is being approached. Read only.
+ * As written to display, taking ABM and backlight lut into account.
+ * Ranges from 0x0 to 0x10000 (= 100% PWM)
+ */
+static int target_backlight_read(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct dc *dc = adev->dm.dc;
+ unsigned int backlight = dc_get_target_backlight_pwm(dc);
+
+ seq_printf(m, "0x%x\n", backlight);
+ return 0;
+}
+
+static const struct drm_info_list amdgpu_dm_debugfs_list[] = {
+ {"amdgpu_current_backlight_pwm", &current_backlight_read},
+ {"amdgpu_target_backlight_pwm", &target_backlight_read},
+};
+
int dtn_debugfs_init(struct amdgpu_device *adev)
{
static const struct file_operations dtn_log_fops = {
@@ -793,9 +852,15 @@ int dtn_debugfs_init(struct amdgpu_device *adev)
};
struct drm_minor *minor = adev->ddev->primary;
- struct dentry *root = minor->debugfs_root;
+ struct dentry *ent, *root = minor->debugfs_root;
+ int ret;
+
+ ret = amdgpu_debugfs_add_files(adev, amdgpu_dm_debugfs_list,
+ ARRAY_SIZE(amdgpu_dm_debugfs_list));
+ if (ret)
+ return ret;
- struct dentry *ent = debugfs_create_file(
+ ent = debugfs_create_file(
"amdgpu_dm_dtn_log",
0644,
root,
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 39997d977efb..b39766bd2840 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
@@ -29,7 +29,7 @@
#include <linux/i2c.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_edid.h>
@@ -192,7 +192,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
int bpp = 0;
int pbn = 0;
- aconnector = stream->sink->priv;
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
if (!aconnector || !aconnector->mst_port)
return false;
@@ -205,7 +205,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
mst_port = aconnector->port;
if (enable) {
- clock = stream->timing.pix_clk_khz;
+ clock = stream->timing.pix_clk_100hz / 10;
switch (stream->timing.display_color_depth) {
@@ -263,6 +263,13 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
return true;
}
+/*
+ * poll pending down reply before clear payload allocation table
+ */
+void dm_helpers_dp_mst_poll_pending_down_reply(
+ struct dc_context *ctx,
+ const struct dc_link *link)
+{}
/*
* Clear payload allocation table before enable MST DP link.
@@ -284,7 +291,7 @@ bool dm_helpers_dp_mst_poll_for_allocation_change_trigger(
struct drm_dp_mst_topology_mgr *mst_mgr;
int ret;
- aconnector = stream->sink->priv;
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
if (!aconnector || !aconnector->mst_port)
return false;
@@ -312,7 +319,7 @@ bool dm_helpers_dp_mst_send_payload_allocation(
struct drm_dp_mst_port *mst_port;
int ret;
- aconnector = stream->sink->priv;
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
if (!aconnector || !aconnector->mst_port)
return false;
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 24632727e127..f51d52eb52e6 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
@@ -35,6 +35,8 @@
#include "dc_link_ddc.h"
+#include "i2caux_interface.h"
+
/* #define TRACE_DPCD */
#ifdef TRACE_DPCD
@@ -81,80 +83,24 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
ssize_t result = 0;
- enum i2caux_transaction_action action;
- enum aux_transaction_type type;
+ struct aux_payload payload;
if (WARN_ON(msg->size > 16))
return -E2BIG;
- switch (msg->request & ~DP_AUX_I2C_MOT) {
- case DP_AUX_NATIVE_READ:
- type = AUX_TRANSACTION_TYPE_DP;
- action = I2CAUX_TRANSACTION_ACTION_DP_READ;
-
- result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service,
- msg->address,
- &msg->reply,
- msg->buffer,
- msg->size,
- type,
- action);
- break;
- case DP_AUX_NATIVE_WRITE:
- type = AUX_TRANSACTION_TYPE_DP;
- action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
-
- dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service,
- msg->address,
- &msg->reply,
- msg->buffer,
- msg->size,
- type,
- action);
- result = msg->size;
- break;
- case DP_AUX_I2C_READ:
- type = AUX_TRANSACTION_TYPE_I2C;
- if (msg->request & DP_AUX_I2C_MOT)
- action = I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
- else
- action = I2CAUX_TRANSACTION_ACTION_I2C_READ;
-
- result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service,
- msg->address,
- &msg->reply,
- msg->buffer,
- msg->size,
- type,
- action);
- break;
- case DP_AUX_I2C_WRITE:
- type = AUX_TRANSACTION_TYPE_I2C;
- if (msg->request & DP_AUX_I2C_MOT)
- action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
- else
- action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
-
- dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service,
- msg->address,
- &msg->reply,
- msg->buffer,
- msg->size,
- type,
- action);
- result = msg->size;
- break;
- default:
- return -EINVAL;
- }
+ payload.address = msg->address;
+ payload.data = msg->buffer;
+ payload.length = msg->size;
+ payload.reply = &msg->reply;
+ payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0;
+ payload.write = (msg->request & DP_AUX_I2C_READ) == 0;
+ payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0;
+ payload.defer_delay = 0;
-#ifdef TRACE_DPCD
- log_dpcd(msg->request,
- msg->address,
- msg->buffer,
- msg->size,
- r == DDC_RESULT_SUCESSFULL);
-#endif
+ result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, &payload);
+
+ if (payload.write)
+ result = msg->size;
if (result < 0) /* DC doesn't know about kernel error codes */
result = -EIO;
@@ -228,6 +174,11 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
aconnector->edid = edid;
}
+ if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) {
+ dc_sink_release(aconnector->dc_sink);
+ aconnector->dc_sink = NULL;
+ }
+
if (!aconnector->dc_sink) {
struct dc_sink *dc_sink;
struct dc_sink_init_data init_params = {
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 9d2d6986b983..a114954d6a5b 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
@@ -25,7 +25,7 @@
#include <linux/acpi.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "dm_services.h"
#include "amdgpu.h"
@@ -559,6 +559,58 @@ void pp_rv_set_pme_wa_enable(struct pp_smu *pp)
pp_funcs->notify_smu_enable_pwe(pp_handle);
}
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
void dm_pp_get_funcs_rv(
struct dc_context *ctx,
struct pp_smu_funcs_rv *funcs)
@@ -567,4 +619,9 @@ void dm_pp_get_funcs_rv(
funcs->set_display_requirement = pp_rv_set_display_requirement;
funcs->set_wm_ranges = pp_rv_set_wm_ranges;
funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable;
+ funcs->set_display_count = pp_rv_set_active_display_count;
+ funcs->set_min_deep_sleep_dcfclk = pp_rv_set_min_deep_sleep_dcfclk;
+ funcs->set_hard_min_dcfclk_by_freq = pp_rv_set_hard_min_dcefclk_by_freq;
+ funcs->set_hard_min_fclk_by_freq = pp_rv_set_hard_min_fclk_by_freq;
}
+
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
index 516795342dd2..d915e8c8769b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
@@ -27,7 +27,7 @@
#include <linux/acpi.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "dm_services.h"
#include "amdgpu.h"
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index aed538a4d1ba..b8ddb4acccdb 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -23,7 +23,7 @@
# Makefile for Display Core (dc) component.
#
-DC_LIBS = basics bios calcs dce gpio i2caux irq virtual
+DC_LIBS = basics bios calcs dce gpio irq virtual
ifdef CONFIG_DRM_AMD_DC_DCN1_0
DC_LIBS += dcn10 dml
@@ -41,7 +41,8 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
include $(AMD_DC)
DISPLAY_CORE = dc.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_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
+dc_vm_helper.o
AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE))
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index c2ab026aee91..a4c97d32e751 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -835,18 +835,6 @@ static enum bp_result bios_parser_enable_crtc(
return bp->cmd_tbl.enable_crtc(bp, id, enable);
}
-static enum bp_result bios_parser_crtc_source_select(
- struct dc_bios *dcb,
- struct bp_crtc_source_select *bp_params)
-{
- struct bios_parser *bp = BP_FROM_DCB(dcb);
-
- if (!bp->cmd_tbl.select_crtc_source)
- return BP_RESULT_FAILURE;
-
- return bp->cmd_tbl.select_crtc_source(bp, bp_params);
-}
-
static enum bp_result bios_parser_enable_disp_power_gating(
struct dc_bios *dcb,
enum controller_id controller_id,
@@ -2842,8 +2830,6 @@ static const struct dc_vbios_funcs vbios_funcs = {
.program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
- .crtc_source_select = bios_parser_crtc_source_select, /* still use. should probably retire and program directly */
-
.program_display_engine_pll = bios_parser_program_display_engine_pll,
.enable_disp_power_gating = bios_parser_enable_disp_power_gating,
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 c513ab6f3843..a1c56f29cfeb 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -1083,18 +1083,6 @@ static enum bp_result bios_parser_enable_crtc(
return bp->cmd_tbl.enable_crtc(bp, id, enable);
}
-static enum bp_result bios_parser_crtc_source_select(
- struct dc_bios *dcb,
- struct bp_crtc_source_select *bp_params)
-{
- struct bios_parser *bp = BP_FROM_DCB(dcb);
-
- if (!bp->cmd_tbl.select_crtc_source)
- return BP_RESULT_FAILURE;
-
- return bp->cmd_tbl.select_crtc_source(bp, bp_params);
-}
-
static enum bp_result bios_parser_enable_disp_power_gating(
struct dc_bios *dcb,
enum controller_id controller_id,
@@ -1899,8 +1887,6 @@ static const struct dc_vbios_funcs vbios_funcs = {
.is_accelerated_mode = bios_parser_is_accelerated_mode,
- .is_active_display = bios_is_active_display,
-
.set_scratch_critical_state = bios_parser_set_scratch_critical_state,
@@ -1917,8 +1903,6 @@ static const struct dc_vbios_funcs vbios_funcs = {
.program_crtc_timing = bios_parser_program_crtc_timing,
- .crtc_source_select = bios_parser_crtc_source_select,
-
.enable_disp_power_gating = bios_parser_enable_disp_power_gating,
.bios_parser_destroy = firmware_parser_destroy,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
index fdda8aa8e303..fce46ab54c54 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
@@ -83,101 +83,7 @@ uint32_t bios_get_vga_enabled_displays(
{
uint32_t active_disp = 1;
- if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/
- active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF;
+ active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF;
return active_disp;
}
-bool bios_is_active_display(
- struct dc_bios *bios,
- enum signal_type signal,
- const struct connector_device_tag_info *device_tag)
-{
- uint32_t active = 0;
- uint32_t connected = 0;
- uint32_t bios_scratch_0 = 0;
- uint32_t bios_scratch_3 = 0;
-
- switch (signal) {
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- {
- if (device_tag->dev_id.device_type == DEVICE_TYPE_DFP) {
- switch (device_tag->dev_id.enum_id) {
- case 1:
- {
- active = ATOM_S3_DFP1_ACTIVE;
- connected = 0x0008; //ATOM_DISPLAY_DFP1_CONNECT
- }
- break;
-
- case 2:
- {
- active = ATOM_S3_DFP2_ACTIVE;
- connected = 0x0080; //ATOM_DISPLAY_DFP2_CONNECT
- }
- break;
-
- case 3:
- {
- active = ATOM_S3_DFP3_ACTIVE;
- connected = 0x0200; //ATOM_DISPLAY_DFP3_CONNECT
- }
- break;
-
- case 4:
- {
- active = ATOM_S3_DFP4_ACTIVE;
- connected = 0x0400; //ATOM_DISPLAY_DFP4_CONNECT
- }
- break;
-
- case 5:
- {
- active = ATOM_S3_DFP5_ACTIVE;
- connected = 0x0800; //ATOM_DISPLAY_DFP5_CONNECT
- }
- break;
-
- case 6:
- {
- active = ATOM_S3_DFP6_ACTIVE;
- connected = 0x0040; //ATOM_DISPLAY_DFP6_CONNECT
- }
- break;
-
- default:
- break;
- }
- }
- }
- break;
-
- case SIGNAL_TYPE_LVDS:
- case SIGNAL_TYPE_EDP:
- {
- active = ATOM_S3_LCD1_ACTIVE;
- connected = 0x0002; //ATOM_DISPLAY_LCD1_CONNECT
- }
- break;
-
- default:
- break;
- }
-
-
- if (bios->regs->BIOS_SCRATCH_0) /*follow up with other asic, todo*/
- bios_scratch_0 = REG_READ(BIOS_SCRATCH_0);
- if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/
- bios_scratch_3 = REG_READ(BIOS_SCRATCH_3);
-
- bios_scratch_3 &= ATOM_S3_DEVICE_ACTIVE_MASK;
- if ((active & bios_scratch_3) && (connected & bios_scratch_0))
- return true;
-
- return false;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
index f33cac2147e3..75a29e68fb27 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
@@ -35,10 +35,6 @@ bool bios_is_accelerated_mode(struct dc_bios *bios);
void bios_set_scratch_acc_mode_change(struct dc_bios *bios);
void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios);
-bool bios_is_active_display(
- struct dc_bios *bios,
- enum signal_type signal,
- const struct connector_device_tag_info *device_tag);
#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
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 2bd7cd97e00d..5815983caaf8 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c
@@ -55,7 +55,6 @@ static void init_adjust_display_pll(struct bios_parser *bp);
static void init_dac_encoder_control(struct bios_parser *bp);
static void init_dac_output_control(struct bios_parser *bp);
static void init_set_crtc_timing(struct bios_parser *bp);
-static void init_select_crtc_source(struct bios_parser *bp);
static void init_enable_crtc(struct bios_parser *bp);
static void init_enable_crtc_mem_req(struct bios_parser *bp);
static void init_external_encoder_control(struct bios_parser *bp);
@@ -73,7 +72,6 @@ void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp)
init_dac_encoder_control(bp);
init_dac_output_control(bp);
init_set_crtc_timing(bp);
- init_select_crtc_source(bp);
init_enable_crtc(bp);
init_enable_crtc_mem_req(bp);
init_program_clock(bp);
@@ -964,9 +962,9 @@ static enum bp_result set_pixel_clock_v3(
allocation.sPCLKInput.ucPostDiv =
(uint8_t)bp_params->pixel_clock_post_divider;
- /* We need to convert from KHz units into 10KHz units */
+ /* We need to convert from 100Hz units into 10KHz units */
allocation.sPCLKInput.usPixelClock =
- cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
+ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100));
params = (PIXEL_CLOCK_PARAMETERS_V3 *)&allocation.sPCLKInput;
params->ucTransmitterId =
@@ -1042,9 +1040,9 @@ static enum bp_result set_pixel_clock_v5(
(uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
bp_params->signal_type, false);
- /* We need to convert from KHz units into 10KHz units */
+ /* We need to convert from 100Hz units into 10KHz units */
clk.sPCLKInput.usPixelClock =
- cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
+ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100));
if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
clk.sPCLKInput.ucMiscInfo |=
@@ -1118,9 +1116,9 @@ static enum bp_result set_pixel_clock_v6(
(uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom(
bp_params->signal_type, false);
- /* We need to convert from KHz units into 10KHz units */
+ /* We need to convert from 100 Hz units into 10KHz units */
clk.sPCLKInput.ulCrtcPclkFreq.ulPixelClock =
- cpu_to_le32(bp_params->target_pixel_clock / 10);
+ cpu_to_le32(bp_params->target_pixel_clock_100hz / 100);
if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) {
clk.sPCLKInput.ucMiscInfo |=
@@ -1182,8 +1180,7 @@ static enum bp_result set_pixel_clock_v7(
clk.ucTransmitterID = bp->cmd_helper->encoder_id_to_atom(dal_graphics_object_id_get_encoder_id(bp_params->encoder_object_id));
clk.ucEncoderMode = (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom(bp_params->signal_type, false);
- /* We need to convert from KHz units into 10KHz units */
- clk.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock * 10);
+ clk.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock_100hz);
clk.ucDeepColorRatio = (uint8_t) bp->cmd_helper->transmitter_color_depth_to_atom(bp_params->color_depth);
@@ -1899,120 +1896,6 @@ static enum bp_result set_crtc_using_dtd_timing_v3(
/*******************************************************************************
********************************************************************************
**
- ** SELECT CRTC SOURCE
- **
- ********************************************************************************
- *******************************************************************************/
-
-static enum bp_result select_crtc_source_v2(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params);
-static enum bp_result select_crtc_source_v3(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params);
-
-static void init_select_crtc_source(struct bios_parser *bp)
-{
- switch (BIOS_CMD_TABLE_PARA_REVISION(SelectCRTC_Source)) {
- case 2:
- bp->cmd_tbl.select_crtc_source = select_crtc_source_v2;
- break;
- case 3:
- bp->cmd_tbl.select_crtc_source = select_crtc_source_v3;
- break;
- default:
- dm_output_to_console("Don't select_crtc_source enable_crtc for v%d\n",
- BIOS_CMD_TABLE_PARA_REVISION(SelectCRTC_Source));
- bp->cmd_tbl.select_crtc_source = NULL;
- break;
- }
-}
-
-static enum bp_result select_crtc_source_v2(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params)
-{
- enum bp_result result = BP_RESULT_FAILURE;
- SELECT_CRTC_SOURCE_PARAMETERS_V2 params;
- uint8_t atom_controller_id;
- uint32_t atom_engine_id;
- enum signal_type s = bp_params->signal;
-
- memset(&params, 0, sizeof(params));
-
- /* set controller id */
- if (bp->cmd_helper->controller_id_to_atom(
- bp_params->controller_id, &atom_controller_id))
- params.ucCRTC = atom_controller_id;
- else
- return BP_RESULT_FAILURE;
-
- /* set encoder id */
- if (bp->cmd_helper->engine_bp_to_atom(
- bp_params->engine_id, &atom_engine_id))
- params.ucEncoderID = (uint8_t)atom_engine_id;
- else
- return BP_RESULT_FAILURE;
-
- if (SIGNAL_TYPE_EDP == s ||
- (SIGNAL_TYPE_DISPLAY_PORT == s &&
- SIGNAL_TYPE_LVDS == bp_params->sink_signal))
- s = SIGNAL_TYPE_LVDS;
-
- params.ucEncodeMode =
- (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
- s, bp_params->enable_dp_audio);
-
- if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params))
- result = BP_RESULT_OK;
-
- return result;
-}
-
-static enum bp_result select_crtc_source_v3(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params)
-{
- bool result = BP_RESULT_FAILURE;
- SELECT_CRTC_SOURCE_PARAMETERS_V3 params;
- uint8_t atom_controller_id;
- uint32_t atom_engine_id;
- enum signal_type s = bp_params->signal;
-
- memset(&params, 0, sizeof(params));
-
- if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id,
- &atom_controller_id))
- params.ucCRTC = atom_controller_id;
- else
- return result;
-
- if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id,
- &atom_engine_id))
- params.ucEncoderID = (uint8_t)atom_engine_id;
- else
- return result;
-
- if (SIGNAL_TYPE_EDP == s ||
- (SIGNAL_TYPE_DISPLAY_PORT == s &&
- SIGNAL_TYPE_LVDS == bp_params->sink_signal))
- s = SIGNAL_TYPE_LVDS;
-
- params.ucEncodeMode =
- bp->cmd_helper->encoder_mode_bp_to_atom(
- s, bp_params->enable_dp_audio);
- /* Needed for VBIOS Random Spatial Dithering feature */
- params.ucDstBpc = (uint8_t)(bp_params->display_output_bit_depth);
-
- if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params))
- result = BP_RESULT_OK;
-
- return result;
-}
-
-/*******************************************************************************
- ********************************************************************************
- **
** ENABLE CRTC
**
********************************************************************************
@@ -2164,7 +2047,7 @@ static enum bp_result program_clock_v5(
/* We need to convert from KHz units into 10KHz units */
params.sPCLKInput.ucPpll = (uint8_t) atom_pll_id;
params.sPCLKInput.usPixelClock =
- cpu_to_le16((uint16_t) (bp_params->target_pixel_clock / 10));
+ cpu_to_le16((uint16_t) (bp_params->target_pixel_clock_100hz / 100));
params.sPCLKInput.ucCRTC = (uint8_t) ATOM_CRTC_INVALID;
if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
@@ -2196,7 +2079,7 @@ static enum bp_result program_clock_v6(
/* We need to convert from KHz units into 10KHz units */
params.sPCLKInput.ucPpll = (uint8_t)atom_pll_id;
params.sPCLKInput.ulDispEngClkFreq =
- cpu_to_le32(bp_params->target_pixel_clock / 10);
+ cpu_to_le32(bp_params->target_pixel_clock_100hz / 100);
if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.h b/drivers/gpu/drm/amd/display/dc/bios/command_table.h
index 94f3d43a7471..ad533775e724 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.h
@@ -71,9 +71,6 @@ struct cmd_tbl {
enum bp_result (*set_crtc_timing)(
struct bios_parser *bp,
struct bp_hw_crtc_timing_parameters *bp_params);
- enum bp_result (*select_crtc_source)(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params);
enum bp_result (*enable_crtc)(
struct bios_parser *bp,
enum controller_id controller_id,
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 2b5dc499a35e..bb2e8105e6ab 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -301,17 +301,17 @@ static enum bp_result set_pixel_clock_v7(
cmd_helper->encoder_mode_bp_to_atom(
bp_params->signal_type, false);
- /* We need to convert from KHz units into 10KHz units */
- clk.pixclk_100hz = cpu_to_le32(bp_params->target_pixel_clock *
- 10);
+ clk.pixclk_100hz = cpu_to_le32(bp_params->target_pixel_clock_100hz);
clk.deep_color_ratio =
(uint8_t) bp->cmd_helper->
transmitter_color_depth_to_atom(
bp_params->color_depth);
- DC_LOG_BIOS("%s:program display clock = %d"\
- "colorDepth = %d\n", __func__,\
- bp_params->target_pixel_clock, bp_params->color_depth);
+
+ DC_LOG_BIOS("%s:program display clock = %d, tg = %d, pll = %d, "\
+ "colorDepth = %d\n", __func__,
+ bp_params->target_pixel_clock_100hz, (int)controller_id,
+ pll_id, bp_params->color_depth);
if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
clk.miscinfo |= PIXEL_CLOCK_V7_MISC_FORCE_PROG_PPLL;
@@ -463,75 +463,6 @@ static enum bp_result set_crtc_using_dtd_timing_v3(
/******************************************************************************
******************************************************************************
**
- ** SELECT CRTC SOURCE
- **
- ******************************************************************************
- *****************************************************************************/
-
-
-static enum bp_result select_crtc_source_v3(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params);
-
-static void init_select_crtc_source(struct bios_parser *bp)
-{
- switch (BIOS_CMD_TABLE_PARA_REVISION(selectcrtc_source)) {
- case 3:
- bp->cmd_tbl.select_crtc_source = select_crtc_source_v3;
- break;
- default:
- dm_output_to_console("Don't select_crtc_source enable_crtc for v%d\n",
- BIOS_CMD_TABLE_PARA_REVISION(selectcrtc_source));
- bp->cmd_tbl.select_crtc_source = NULL;
- break;
- }
-}
-
-
-static enum bp_result select_crtc_source_v3(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params)
-{
- bool result = BP_RESULT_FAILURE;
- struct select_crtc_source_parameters_v2_3 params;
- uint8_t atom_controller_id;
- uint32_t atom_engine_id;
- enum signal_type s = bp_params->signal;
-
- memset(&params, 0, sizeof(params));
-
- if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id,
- &atom_controller_id))
- params.crtc_id = atom_controller_id;
- else
- return result;
-
- if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id,
- &atom_engine_id))
- params.encoder_id = (uint8_t)atom_engine_id;
- else
- return result;
-
- if (s == SIGNAL_TYPE_EDP ||
- (s == SIGNAL_TYPE_DISPLAY_PORT && bp_params->sink_signal ==
- SIGNAL_TYPE_LVDS))
- s = SIGNAL_TYPE_LVDS;
-
- params.encode_mode =
- bp->cmd_helper->encoder_mode_bp_to_atom(
- s, bp_params->enable_dp_audio);
- /* Needed for VBIOS Random Spatial Dithering feature */
- params.dst_bpc = (uint8_t)(bp_params->display_output_bit_depth);
-
- if (EXEC_BIOS_CMD_TABLE(selectcrtc_source, params))
- result = BP_RESULT_OK;
-
- return result;
-}
-
-/******************************************************************************
- ******************************************************************************
- **
** ENABLE CRTC
**
******************************************************************************
@@ -808,7 +739,6 @@ void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp)
init_set_crtc_timing(bp);
- init_select_crtc_source(bp);
init_enable_crtc(bp);
init_external_encoder_control(bp);
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
index ec1c0c9f3f1d..7a2af24dfe60 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
@@ -71,9 +71,6 @@ struct cmd_tbl {
enum bp_result (*set_crtc_timing)(
struct bios_parser *bp,
struct bp_hw_crtc_timing_parameters *bp_params);
- enum bp_result (*select_crtc_source)(
- struct bios_parser *bp,
- struct bp_crtc_source_select *bp_params);
enum bp_result (*enable_crtc)(
struct bios_parser *bp,
enum controller_id controller_id,
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
index 9ebe30ba4dab..f3aa7b53d2aa 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
@@ -2792,7 +2792,7 @@ static void populate_initial_data(
data->lpt_en[num_displays + 4] = false;
data->h_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.h_total);
data->v_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.v_total);
- data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pipe[i].stream->timing.pix_clk_khz, 1000);
+ data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pipe[i].stream->timing.pix_clk_100hz, 10000);
data->src_width[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.width);
data->pitch_in_pixels[num_displays + 4] = data->src_width[num_displays + 4];
data->src_height[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.height);
@@ -2881,7 +2881,7 @@ static void populate_initial_data(
/* Pipes without underlay after */
for (i = 0; i < pipe_count; i++) {
- unsigned int pixel_clock_khz;
+ unsigned int pixel_clock_100hz;
if (!pipe[i].stream || pipe[i].bottom_pipe)
continue;
@@ -2890,10 +2890,10 @@ static void populate_initial_data(
data->lpt_en[num_displays + 4] = false;
data->h_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.h_total);
data->v_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.v_total);
- pixel_clock_khz = pipe[i].stream->timing.pix_clk_khz;
+ pixel_clock_100hz = pipe[i].stream->timing.pix_clk_100hz;
if (pipe[i].stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
- pixel_clock_khz *= 2;
- data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pixel_clock_khz, 1000);
+ pixel_clock_100hz *= 2;
+ data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pixel_clock_100hz, 10000);
if (pipe[i].plane_state) {
data->src_width[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.width);
data->pitch_in_pixels[num_displays + 4] = data->src_width[num_displays + 4];
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c
index d0fc54f8fb1c..1ef0074302c5 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c
+++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c
@@ -63,7 +63,7 @@ void scaler_settings_calculation(struct dcn_bw_internal_vars *v)
if (v->interlace_output[k] == 1.0) {
v->v_ratio[k] = 2.0 * v->v_ratio[k];
}
- if ((v->underscan_output[k] == 1.0)) {
+ if (v->underscan_output[k] == 1.0) {
v->h_ratio[k] = v->h_ratio[k] * v->under_scan_factor;
v->v_ratio[k] = v->v_ratio[k] * v->under_scan_factor;
}
@@ -797,9 +797,40 @@ void mode_support_and_system_configuration(struct dcn_bw_internal_vars *v)
else {
v->maximum_vstartup = v->v_sync_plus_back_porch[k] - 1.0;
}
- v->line_times_for_prefetch[k] = v->maximum_vstartup - v->urgent_latency / (v->htotal[k] / v->pixel_clock[k]) - (v->time_calc + v->time_setup) / (v->htotal[k] / v->pixel_clock[k]) - (v->dst_y_after_scaler + v->dst_x_after_scaler / v->htotal[k]);
- v->line_times_for_prefetch[k] =dcn_bw_floor2(4.0 * (v->line_times_for_prefetch[k] + 0.125), 1.0) / 4;
- v->prefetch_bw[k] = (v->meta_pte_bytes_per_frame[k] + 2.0 * v->meta_row_bytes[k] + 2.0 * v->dpte_bytes_per_row[k] + v->prefetch_lines_y[k] * v->swath_width_yper_state[i][j][k] *dcn_bw_ceil2(v->byte_per_pixel_in_dety[k], 1.0) + v->prefetch_lines_c[k] * v->swath_width_yper_state[i][j][k] / 2.0 *dcn_bw_ceil2(v->byte_per_pixel_in_detc[k], 2.0)) / (v->line_times_for_prefetch[k] * v->htotal[k] / v->pixel_clock[k]);
+
+ do {
+ v->line_times_for_prefetch[k] = v->maximum_vstartup - v->urgent_latency / (v->htotal[k] / v->pixel_clock[k]) - (v->time_calc + v->time_setup) / (v->htotal[k] / v->pixel_clock[k]) - (v->dst_y_after_scaler + v->dst_x_after_scaler / v->htotal[k]);
+ v->line_times_for_prefetch[k] =dcn_bw_floor2(4.0 * (v->line_times_for_prefetch[k] + 0.125), 1.0) / 4;
+ v->prefetch_bw[k] = (v->meta_pte_bytes_per_frame[k] + 2.0 * v->meta_row_bytes[k] + 2.0 * v->dpte_bytes_per_row[k] + v->prefetch_lines_y[k] * v->swath_width_yper_state[i][j][k] *dcn_bw_ceil2(v->byte_per_pixel_in_dety[k], 1.0) + v->prefetch_lines_c[k] * v->swath_width_yper_state[i][j][k] / 2.0 *dcn_bw_ceil2(v->byte_per_pixel_in_detc[k], 2.0)) / (v->line_times_for_prefetch[k] * v->htotal[k] / v->pixel_clock[k]);
+
+ if (v->pte_enable == dcn_bw_yes && v->dcc_enable[k] == dcn_bw_yes) {
+ v->time_for_meta_pte_without_immediate_flip = dcn_bw_max3(
+ v->meta_pte_bytes_frame[k] / v->prefetch_bandwidth[k],
+ v->extra_latency,
+ v->htotal[k] / v->pixel_clock[k] / 4.0);
+ } else {
+ v->time_for_meta_pte_without_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0;
+ }
+
+ if (v->pte_enable == dcn_bw_yes || v->dcc_enable[k] == dcn_bw_yes) {
+ v->time_for_meta_and_dpte_row_without_immediate_flip = dcn_bw_max3((
+ v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bandwidth[k],
+ v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip,
+ v->extra_latency);
+ } else {
+ v->time_for_meta_and_dpte_row_without_immediate_flip = dcn_bw_max2(
+ v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip,
+ v->extra_latency - v->time_for_meta_pte_with_immediate_flip);
+ }
+
+ v->lines_for_meta_pte_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
+ v->lines_for_meta_and_dpte_row_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
+ v->maximum_vstartup = v->maximum_vstartup - 1;
+
+ if (v->lines_for_meta_pte_without_immediate_flip[k] < 8.0 && v->lines_for_meta_and_dpte_row_without_immediate_flip[k] < 16.0)
+ break;
+
+ } while(1);
}
v->bw_available_for_immediate_flip = v->return_bw_per_state[i];
for (k = 0; k <= v->number_of_active_planes - 1; k++) {
@@ -814,24 +845,18 @@ void mode_support_and_system_configuration(struct dcn_bw_internal_vars *v)
for (k = 0; k <= v->number_of_active_planes - 1; k++) {
if (v->pte_enable == dcn_bw_yes && v->dcc_enable[k] == dcn_bw_yes) {
v->time_for_meta_pte_with_immediate_flip =dcn_bw_max5(v->meta_pte_bytes_per_frame[k] / v->prefetch_bw[k], v->meta_pte_bytes_per_frame[k] * v->total_immediate_flip_bytes[k] / (v->bw_available_for_immediate_flip * (v->meta_pte_bytes_per_frame[k] + v->meta_row_bytes[k] + v->dpte_bytes_per_row[k])), v->extra_latency, v->urgent_latency, v->htotal[k] / v->pixel_clock[k] / 4.0);
- v->time_for_meta_pte_without_immediate_flip =dcn_bw_max3(v->meta_pte_bytes_per_frame[k] / v->prefetch_bw[k], v->extra_latency, v->htotal[k] / v->pixel_clock[k] / 4.0);
}
else {
v->time_for_meta_pte_with_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0;
- v->time_for_meta_pte_without_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0;
}
if (v->pte_enable == dcn_bw_yes || v->dcc_enable[k] == dcn_bw_yes) {
v->time_for_meta_and_dpte_row_with_immediate_flip =dcn_bw_max5((v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bw[k], (v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) * v->total_immediate_flip_bytes[k] / (v->bw_available_for_immediate_flip * (v->meta_pte_bytes_per_frame[k] + v->meta_row_bytes[k] + v->dpte_bytes_per_row[k])), v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_with_immediate_flip, v->extra_latency, 2.0 * v->urgent_latency);
- v->time_for_meta_and_dpte_row_without_immediate_flip =dcn_bw_max3((v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bw[k], v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, v->extra_latency);
}
else {
v->time_for_meta_and_dpte_row_with_immediate_flip =dcn_bw_max2(v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_with_immediate_flip, v->extra_latency - v->time_for_meta_pte_with_immediate_flip);
- v->time_for_meta_and_dpte_row_without_immediate_flip =dcn_bw_max2(v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, v->extra_latency - v->time_for_meta_pte_without_immediate_flip);
}
v->lines_for_meta_pte_with_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_with_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
- v->lines_for_meta_pte_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
v->lines_for_meta_and_dpte_row_with_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_with_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
- v->lines_for_meta_and_dpte_row_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4;
v->line_times_to_request_prefetch_pixel_data_with_immediate_flip = v->line_times_for_prefetch[k] - v->lines_for_meta_pte_with_immediate_flip[k] - v->lines_for_meta_and_dpte_row_with_immediate_flip[k];
v->line_times_to_request_prefetch_pixel_data_without_immediate_flip = v->line_times_for_prefetch[k] - v->lines_for_meta_pte_without_immediate_flip[k] - v->lines_for_meta_and_dpte_row_without_immediate_flip[k];
if (v->line_times_to_request_prefetch_pixel_data_with_immediate_flip > 0.0) {
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
index 43e4a2be0fa6..12d1842079ae 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
@@ -290,41 +290,34 @@ static void pipe_ctx_to_e2e_pipe_params (
switch (pipe->plane_state->tiling_info.gfx9.swizzle) {
/* for 4/8/16 high tiles */
case DC_SW_LINEAR:
- input->src.is_display_sw = 1;
input->src.macro_tile_size = dm_4k_tile;
break;
case DC_SW_4KB_S:
case DC_SW_4KB_S_X:
- input->src.is_display_sw = 0;
input->src.macro_tile_size = dm_4k_tile;
break;
case DC_SW_64KB_S:
case DC_SW_64KB_S_X:
case DC_SW_64KB_S_T:
- input->src.is_display_sw = 0;
input->src.macro_tile_size = dm_64k_tile;
break;
case DC_SW_VAR_S:
case DC_SW_VAR_S_X:
- input->src.is_display_sw = 0;
input->src.macro_tile_size = dm_256k_tile;
break;
/* For 64bpp 2 high tiles */
case DC_SW_4KB_D:
case DC_SW_4KB_D_X:
- input->src.is_display_sw = 1;
input->src.macro_tile_size = dm_4k_tile;
break;
case DC_SW_64KB_D:
case DC_SW_64KB_D_X:
case DC_SW_64KB_D_T:
- input->src.is_display_sw = 1;
input->src.macro_tile_size = dm_64k_tile;
break;
case DC_SW_VAR_D:
case DC_SW_VAR_D_X:
- input->src.is_display_sw = 1;
input->src.macro_tile_size = dm_256k_tile;
break;
@@ -423,7 +416,7 @@ static void pipe_ctx_to_e2e_pipe_params (
- pipe->stream->timing.v_addressable
- pipe->stream->timing.v_border_bottom
- pipe->stream->timing.v_border_top;
- input->dest.pixel_rate_mhz = pipe->stream->timing.pix_clk_khz/1000.0;
+ input->dest.pixel_rate_mhz = pipe->stream->timing.pix_clk_100hz/10000.0;
input->dest.vstartup_start = pipe->pipe_dlg_param.vstartup_start;
input->dest.vupdate_offset = pipe->pipe_dlg_param.vupdate_offset;
input->dest.vupdate_offset = pipe->pipe_dlg_param.vupdate_offset;
@@ -670,9 +663,9 @@ static void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v)
}
static void hack_force_pipe_split(struct dcn_bw_internal_vars *v,
- unsigned int pixel_rate_khz)
+ unsigned int pixel_rate_100hz)
{
- float pixel_rate_mhz = pixel_rate_khz / 1000;
+ float pixel_rate_mhz = pixel_rate_100hz / 10000;
/*
* force enabling pipe split by lower dpp clock for DPM0 to just
@@ -695,7 +688,7 @@ static void hack_bounding_box(struct dcn_bw_internal_vars *v,
if (context->stream_count == 1 &&
dbg->force_single_disp_pipe_split)
- hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_khz);
+ hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_100hz);
}
bool dcn_validate_bandwidth(
@@ -852,7 +845,7 @@ bool dcn_validate_bandwidth(
v->v_sync_plus_back_porch[input_idx] = pipe->stream->timing.v_total
- v->vactive[input_idx]
- pipe->stream->timing.v_front_porch;
- v->pixel_clock[input_idx] = pipe->stream->timing.pix_clk_khz/1000.0;
+ v->pixel_clock[input_idx] = pipe->stream->timing.pix_clk_100hz/10000.0;
if (pipe->stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
v->pixel_clock[input_idx] *= 2;
if (!pipe->plane_state) {
@@ -961,7 +954,7 @@ bool dcn_validate_bandwidth(
v->dcc_rate[input_idx] = 1; /*TODO: Worst case? does this change?*/
v->output_format[input_idx] = pipe->stream->timing.pixel_encoding ==
PIXEL_ENCODING_YCBCR420 ? dcn_bw_420 : dcn_bw_444;
- v->output[input_idx] = pipe->stream->sink->sink_signal ==
+ v->output[input_idx] = pipe->stream->signal ==
SIGNAL_TYPE_HDMI_TYPE_A ? dcn_bw_hdmi : dcn_bw_dp;
v->output_deep_color[input_idx] = dcn_bw_encoder_8bpc;
if (v->output[input_idx] == dcn_bw_hdmi) {
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 5fd52094d459..52f838442e21 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -384,7 +384,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream,
enum dc_dither_option option)
{
struct bit_depth_reduction_params params;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
struct pipe_ctx *pipes = NULL;
int i;
@@ -451,7 +451,7 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
pipes,
stream->output_color_space,
stream->csc_color_matrix.matrix,
- pipes->plane_res.hubp->opp_id);
+ pipes->plane_res.hubp ? pipes->plane_res.hubp->opp_id : 0);
ret = true;
}
}
@@ -526,9 +526,8 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream && pipe->stream->sink
- && pipe->stream->sink->link) {
- if (pipe->stream->sink->link == link)
+ if (pipe->stream && pipe->stream->link) {
+ if (pipe->stream->link == link)
break;
}
}
@@ -586,9 +585,6 @@ static void destruct(struct dc *dc)
if (dc->ctx->gpio_service)
dal_gpio_service_destroy(&dc->ctx->gpio_service);
- if (dc->ctx->i2caux)
- dal_i2caux_destroy(&dc->ctx->i2caux);
-
if (dc->ctx->created_bios)
dal_bios_parser_destroy(&dc->ctx->dc_bios);
@@ -625,7 +621,6 @@ static bool construct(struct dc *dc,
#endif
enum dce_version dc_version = DCE_VERSION_UNKNOWN;
-
dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL);
if (!dc_dceip) {
dm_error("%s: failed to create dceip\n", __func__);
@@ -670,6 +665,7 @@ static bool construct(struct dc *dc,
dc_ctx->dc = dc;
dc_ctx->asic_id = init_params->asic_id;
dc_ctx->dc_sink_id_count = 0;
+ dc_ctx->dc_stream_id_count = 0;
dc->ctx = dc_ctx;
dc->current_state = dc_create_state();
@@ -709,14 +705,6 @@ static bool construct(struct dc *dc,
dc_ctx->created_bios = true;
}
- /* Create I2C AUX */
- dc_ctx->i2caux = dal_i2caux_create(dc_ctx);
-
- if (!dc_ctx->i2caux) {
- ASSERT_CRITICAL(false);
- goto fail;
- }
-
dc_ctx->perf_trace = dc_perf_trace_create();
if (!dc_ctx->perf_trace) {
ASSERT_CRITICAL(false);
@@ -840,6 +828,11 @@ alloc_fail:
return NULL;
}
+void dc_init_callbacks(struct dc *dc,
+ const struct dc_callback_init *init_params)
+{
+}
+
void dc_destroy(struct dc **dc)
{
destruct(*dc);
@@ -875,8 +868,9 @@ static void program_timing_sync(
struct dc *dc,
struct dc_state *ctx)
{
- int i, j;
+ int i, j, k;
int group_index = 0;
+ int num_group = 0;
int pipe_count = dc->res_pool->pipe_count;
struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL };
@@ -913,11 +907,11 @@ static void program_timing_sync(
}
}
- /* set first unblanked pipe as master */
+ /* set first pipe with plane as master */
for (j = 0; j < group_size; j++) {
struct pipe_ctx *temp;
- if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) {
+ if (pipe_set[j]->plane_state) {
if (j == 0)
break;
@@ -928,9 +922,21 @@ static void program_timing_sync(
}
}
- /* remove any other unblanked pipes as they have already been synced */
+
+ for (k = 0; k < group_size; k++) {
+ struct dc_stream_status *status = dc_stream_get_status_from_state(ctx, pipe_set[k]->stream);
+
+ status->timing_sync_info.group_id = num_group;
+ status->timing_sync_info.group_size = group_size;
+ if (k == 0)
+ status->timing_sync_info.master = true;
+ else
+ status->timing_sync_info.master = false;
+
+ }
+ /* remove any other pipes with plane as they have already been synced */
for (j = j + 1; j < group_size; j++) {
- if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) {
+ if (pipe_set[j]->plane_state) {
group_size--;
pipe_set[j] = pipe_set[group_size];
j--;
@@ -942,6 +948,7 @@ static void program_timing_sync(
dc, group_index, group_size, pipe_set);
group_index++;
}
+ num_group++;
}
}
@@ -962,6 +969,52 @@ static bool context_changed(
return false;
}
+bool dc_validate_seamless_boot_timing(struct dc *dc,
+ const struct dc_sink *sink,
+ struct dc_crtc_timing *crtc_timing)
+{
+ struct timing_generator *tg;
+ struct dc_link *link = sink->link;
+ unsigned int inst;
+
+ /* Check for enabled DIG to identify enabled display */
+ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ return false;
+
+ /* Check for which front end is used by this encoder.
+ * Note the inst is 1 indexed, where 0 is undefined.
+ * Note that DIG_FE can source from different OTG but our
+ * current implementation always map 1-to-1, so this code makes
+ * the same assumption and doesn't check OTG source.
+ */
+ inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+
+ /* Instance should be within the range of the pool */
+ if (inst >= dc->res_pool->pipe_count)
+ return false;
+
+ tg = dc->res_pool->timing_generators[inst];
+
+ if (!tg->funcs->is_matching_timing)
+ return false;
+
+ if (!tg->funcs->is_matching_timing(tg, crtc_timing))
+ return false;
+
+ if (dc_is_dp_signal(link->connector_signal)) {
+ unsigned int pix_clk_100hz;
+
+ dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
+ dc->res_pool->dp_clock_source,
+ inst, &pix_clk_100hz);
+
+ if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
+ return false;
+ }
+
+ return true;
+}
+
bool dc_enable_stereo(
struct dc *dc,
struct dc_state *context,
@@ -1040,7 +1093,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
/* Program all planes within new context*/
for (i = 0; i < context->stream_count; i++) {
- const struct dc_sink *sink = context->streams[i]->sink;
+ const struct dc_link *link = context->streams[i]->link;
+ struct dc_stream_status *status;
+
+ if (context->streams[i]->apply_seamless_boot_optimization)
+ context->streams[i]->apply_seamless_boot_optimization = false;
if (!context->streams[i]->mode_changed)
continue;
@@ -1065,12 +1122,15 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
}
}
- CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
+ status = dc_stream_get_status_from_state(context, context->streams[i]);
+ context->streams[i]->out.otg_offset = status->primary_otg_inst;
+
+ CONN_MSG_MODE(link, "{%dx%d, %dx%d@%dKhz}",
context->streams[i]->timing.h_addressable,
context->streams[i]->timing.v_addressable,
context->streams[i]->timing.h_total,
context->streams[i]->timing.v_total,
- context->streams[i]->timing.pix_clk_khz);
+ context->streams[i]->timing.pix_clk_100hz / 10);
}
dc_enable_stereo(dc, context, dc_streams, context->stream_count);
@@ -1114,6 +1174,9 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
int i;
struct dc_state *context = dc->current_state;
+ if (dc->optimized_required == false)
+ return true;
+
post_surface_trace(dc);
for (i = 0; i < dc->res_pool->pipe_count; i++)
@@ -1215,6 +1278,12 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
*/
update_flags->bits.bpp_change = 1;
+ if (u->plane_info->plane_size.grph.surface_pitch != u->surface->plane_size.grph.surface_pitch
+ || u->plane_info->plane_size.video.luma_pitch != u->surface->plane_size.video.luma_pitch
+ || u->plane_info->plane_size.video.chroma_pitch != u->surface->plane_size.video.chroma_pitch)
+ update_flags->bits.plane_size_change = 1;
+
+
if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info,
sizeof(union dc_tiling_info)) != 0) {
update_flags->bits.swizzle_change = 1;
@@ -1236,7 +1305,7 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
|| update_flags->bits.output_tf_change)
return UPDATE_TYPE_FULL;
- return UPDATE_TYPE_MED;
+ return update_flags->raw ? UPDATE_TYPE_MED : UPDATE_TYPE_FAST;
}
static enum surface_update_type get_scaling_info_update_type(
@@ -1436,6 +1505,101 @@ static struct dc_stream_status *stream_get_status(
static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
+static void copy_surface_update_to_plane(
+ struct dc_plane_state *surface,
+ struct dc_surface_update *srf_update)
+{
+ if (srf_update->flip_addr) {
+ surface->address = srf_update->flip_addr->address;
+ surface->flip_immediate =
+ srf_update->flip_addr->flip_immediate;
+ surface->time.time_elapsed_in_us[surface->time.index] =
+ srf_update->flip_addr->flip_timestamp_in_us -
+ surface->time.prev_update_time_in_us;
+ surface->time.prev_update_time_in_us =
+ srf_update->flip_addr->flip_timestamp_in_us;
+ surface->time.index++;
+ if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
+ surface->time.index = 0;
+ }
+
+ if (srf_update->scaling_info) {
+ surface->scaling_quality =
+ srf_update->scaling_info->scaling_quality;
+ surface->dst_rect =
+ srf_update->scaling_info->dst_rect;
+ surface->src_rect =
+ srf_update->scaling_info->src_rect;
+ surface->clip_rect =
+ srf_update->scaling_info->clip_rect;
+ }
+
+ if (srf_update->plane_info) {
+ surface->color_space =
+ srf_update->plane_info->color_space;
+ surface->format =
+ srf_update->plane_info->format;
+ surface->plane_size =
+ srf_update->plane_info->plane_size;
+ surface->rotation =
+ srf_update->plane_info->rotation;
+ surface->horizontal_mirror =
+ srf_update->plane_info->horizontal_mirror;
+ surface->stereo_format =
+ srf_update->plane_info->stereo_format;
+ surface->tiling_info =
+ srf_update->plane_info->tiling_info;
+ surface->visible =
+ srf_update->plane_info->visible;
+ surface->per_pixel_alpha =
+ srf_update->plane_info->per_pixel_alpha;
+ surface->global_alpha =
+ srf_update->plane_info->global_alpha;
+ surface->global_alpha_value =
+ srf_update->plane_info->global_alpha_value;
+ surface->dcc =
+ srf_update->plane_info->dcc;
+ surface->sdr_white_level =
+ srf_update->plane_info->sdr_white_level;
+ }
+
+ if (srf_update->gamma &&
+ (surface->gamma_correction !=
+ srf_update->gamma)) {
+ memcpy(&surface->gamma_correction->entries,
+ &srf_update->gamma->entries,
+ sizeof(struct dc_gamma_entries));
+ surface->gamma_correction->is_identity =
+ srf_update->gamma->is_identity;
+ surface->gamma_correction->num_entries =
+ srf_update->gamma->num_entries;
+ surface->gamma_correction->type =
+ srf_update->gamma->type;
+ }
+
+ if (srf_update->in_transfer_func &&
+ (surface->in_transfer_func !=
+ srf_update->in_transfer_func)) {
+ surface->in_transfer_func->sdr_ref_white_level =
+ srf_update->in_transfer_func->sdr_ref_white_level;
+ surface->in_transfer_func->tf =
+ srf_update->in_transfer_func->tf;
+ surface->in_transfer_func->type =
+ srf_update->in_transfer_func->type;
+ memcpy(&surface->in_transfer_func->tf_pts,
+ &srf_update->in_transfer_func->tf_pts,
+ sizeof(struct dc_transfer_func_distributed_points));
+ }
+
+ if (srf_update->input_csc_color_matrix)
+ surface->input_csc_color_matrix =
+ *srf_update->input_csc_color_matrix;
+
+ if (srf_update->coeff_reduction_factor)
+ surface->coeff_reduction_factor =
+ *srf_update->coeff_reduction_factor;
+}
+
static void commit_planes_do_stream_update(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -1459,11 +1623,13 @@ static void commit_planes_do_stream_update(struct dc *dc,
stream_update->adjust->v_total_min,
stream_update->adjust->v_total_max);
- if (stream_update->periodic_fn_vsync_delta &&
- pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
+ if (stream_update->periodic_vsync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
- pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing,
- pipe_ctx->stream->periodic_fn_vsync_delta);
+ pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE0, &stream->periodic_vsync_config);
+
+ if (stream_update->enhanced_sync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
+ pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
+ pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE1, &stream->enhanced_sync_config);
if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
stream_update->vrr_infopacket ||
@@ -1605,7 +1771,6 @@ void dc_commit_updates_for_stream(struct dc *dc,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- struct dc_plane_state **plane_states,
struct dc_state *state)
{
const struct dc_stream_status *stream_status;
@@ -1640,14 +1805,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
for (i = 0; i < surface_count; i++) {
struct dc_plane_state *surface = srf_updates[i].surface;
- /* TODO: On flip we don't build the state, so it still has the
- * old address. Which is why we are updating the address here
- */
- if (srf_updates[i].flip_addr) {
- surface->address = srf_updates[i].flip_addr->address;
- surface->flip_immediate = srf_updates[i].flip_addr->flip_immediate;
-
- }
+ copy_surface_update_to_plane(surface, &srf_updates[i]);
if (update_type >= UPDATE_TYPE_MED) {
for (j = 0; j < dc->res_pool->pipe_count; j++) {
@@ -1764,6 +1922,26 @@ void dc_resume(struct dc *dc)
core_link_resume(dc->links[i]);
}
+unsigned int dc_get_current_backlight_pwm(struct dc *dc)
+{
+ struct abm *abm = dc->res_pool->abm;
+
+ if (abm)
+ return abm->funcs->get_current_backlight(abm);
+
+ return 0;
+}
+
+unsigned int dc_get_target_backlight_pwm(struct dc *dc)
+{
+ struct abm *abm = dc->res_pool->abm;
+
+ if (abm)
+ return abm->funcs->get_target_backlight(abm);
+
+ return 0;
+}
+
bool dc_is_dmcu_initialized(struct dc *dc)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
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 52deacf39841..7f5a947ad31d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -43,10 +43,6 @@
#include "dpcd_defs.h"
#include "dmcu.h"
-#include "dce/dce_11_0_d.h"
-#include "dce/dce_11_0_enum.h"
-#include "dce/dce_11_0_sh_mask.h"
-
#define DC_LOGGER_INIT(logger)
@@ -80,6 +76,12 @@ static void destruct(struct dc_link *link)
{
int i;
+ if (link->hpd_gpio != NULL) {
+ dal_gpio_close(link->hpd_gpio);
+ dal_gpio_destroy_irq(&link->hpd_gpio);
+ link->hpd_gpio = NULL;
+ }
+
if (link->ddc)
dal_ddc_service_destroy(&link->ddc);
@@ -789,7 +791,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
return false;
}
- sink->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock;
+ sink->link->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock;
sink->converter_disable_audio = converter_disable_audio;
link->local_sink = sink;
@@ -935,18 +937,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
bool dc_link_get_hpd_state(struct dc_link *dc_link)
{
- struct gpio *hpd_pin;
uint32_t state;
- hpd_pin = get_hpd_gpio(dc_link->ctx->dc_bios,
- dc_link->link_id, dc_link->ctx->gpio_service);
- if (hpd_pin == NULL)
- ASSERT(false);
-
- dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
- dal_gpio_get_value(hpd_pin, &state);
- dal_gpio_close(hpd_pin);
- dal_gpio_destroy_irq(&hpd_pin);
+ dal_gpio_lock_pin(dc_link->hpd_gpio);
+ dal_gpio_get_value(dc_link->hpd_gpio, &state);
+ dal_gpio_unlock_pin(dc_link->hpd_gpio);
return state;
}
@@ -1102,7 +1097,6 @@ static bool construct(
const struct link_init_data *init_params)
{
uint8_t i;
- struct gpio *hpd_gpio = NULL;
struct ddc_service_init_data ddc_service_init_data = { { 0 } };
struct dc_context *dc_ctx = init_params->ctx;
struct encoder_init_data enc_init_data = { 0 };
@@ -1132,10 +1126,12 @@ static bool construct(
if (link->dc->res_pool->funcs->link_init)
link->dc->res_pool->funcs->link_init(link);
- hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
-
- if (hpd_gpio != NULL)
- link->irq_source_hpd = dal_irq_get_source(hpd_gpio);
+ link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+ if (link->hpd_gpio != NULL) {
+ dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);
+ dal_gpio_unlock_pin(link->hpd_gpio);
+ link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);
+ }
switch (link->link_id.id) {
case CONNECTOR_ID_HDMI_TYPE_A:
@@ -1153,18 +1149,18 @@ static bool construct(
case CONNECTOR_ID_DISPLAY_PORT:
link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
- if (hpd_gpio != NULL)
+ if (link->hpd_gpio != NULL)
link->irq_source_hpd_rx =
- dal_irq_get_rx_source(hpd_gpio);
+ dal_irq_get_rx_source(link->hpd_gpio);
break;
case CONNECTOR_ID_EDP:
link->connector_signal = SIGNAL_TYPE_EDP;
- if (hpd_gpio != NULL) {
+ if (link->hpd_gpio != NULL) {
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
link->irq_source_hpd_rx =
- dal_irq_get_rx_source(hpd_gpio);
+ dal_irq_get_rx_source(link->hpd_gpio);
}
break;
case CONNECTOR_ID_LVDS:
@@ -1175,10 +1171,7 @@ static bool construct(
goto create_fail;
}
- if (hpd_gpio != NULL) {
- dal_gpio_destroy_irq(&hpd_gpio);
- hpd_gpio = NULL;
- }
+
/* TODO: #DAL3 Implement id to str function.*/
LINK_INFO("Connector[%d] description:"
@@ -1281,8 +1274,9 @@ link_enc_create_fail:
ddc_create_fail:
create_fail:
- if (hpd_gpio != NULL) {
- dal_gpio_destroy_irq(&hpd_gpio);
+ if (link->hpd_gpio != NULL) {
+ dal_gpio_destroy_irq(&link->hpd_gpio);
+ link->hpd_gpio = NULL;
}
return false;
@@ -1372,7 +1366,7 @@ static void dpcd_configure_panel_mode(
static void enable_stream_features(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
union down_spread_ctrl old_downspread;
union down_spread_ctrl new_downspread;
@@ -1397,7 +1391,7 @@ static enum dc_status enable_link_dp(
struct dc_stream_state *stream = pipe_ctx->stream;
enum dc_status status;
bool skip_video_pattern;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
struct dc_link_settings link_settings = {0};
enum dp_panel_mode panel_mode;
@@ -1414,8 +1408,8 @@ static enum dc_status enable_link_dp(
pipe_ctx->clock_source->id,
&link_settings);
- if (stream->sink->edid_caps.panel_patch.dppowerup_delay > 0) {
- int delay_dp_power_up_in_ms = stream->sink->edid_caps.panel_patch.dppowerup_delay;
+ if (stream->sink_patches.dppowerup_delay > 0) {
+ int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
msleep(delay_dp_power_up_in_ms);
}
@@ -1448,7 +1442,7 @@ static enum dc_status enable_link_edp(
{
enum dc_status status;
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
/*in case it is not on*/
link->dc->hwss.edp_power_control(link, true);
link->dc->hwss.edp_wait_for_hpd_ready(link, true);
@@ -1463,7 +1457,7 @@ static enum dc_status enable_link_dp_mst(
struct dc_state *state,
struct pipe_ctx *pipe_ctx)
{
- struct dc_link *link = pipe_ctx->stream->sink->link;
+ struct dc_link *link = pipe_ctx->stream->link;
/* sink signal type after MST branch is MST. Multiple MST sinks
* share one link. Link DP PHY is enable or training only once.
@@ -1471,6 +1465,11 @@ static enum dc_status enable_link_dp_mst(
if (link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN)
return DC_OK;
+ /* to make sure the pending down rep can be processed
+ * before clear payload table
+ */
+ dm_helpers_dp_mst_poll_pending_down_reply(link->ctx, link);
+
/* clear payload table */
dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link);
@@ -1597,7 +1596,7 @@ static bool i2c_write(struct pipe_ctx *pipe_ctx,
cmd.payloads = &payload;
if (dm_helpers_submit_i2c(pipe_ctx->stream->ctx,
- pipe_ctx->stream->sink->link, &cmd))
+ pipe_ctx->stream->link, &cmd))
return true;
return false;
@@ -1651,7 +1650,7 @@ static void write_i2c_retimer_setting(
else {
i2c_success =
dal_ddc_service_query_ddc_data(
- pipe_ctx->stream->sink->link->ddc,
+ pipe_ctx->stream->link->ddc,
slave_address, &offset, 1, &value, 1);
if (!i2c_success)
/* Write failure */
@@ -1704,7 +1703,7 @@ static void write_i2c_retimer_setting(
else {
i2c_success =
dal_ddc_service_query_ddc_data(
- pipe_ctx->stream->sink->link->ddc,
+ pipe_ctx->stream->link->ddc,
slave_address, &offset, 1, &value, 1);
if (!i2c_success)
/* Write failure */
@@ -1929,7 +1928,7 @@ static void write_i2c_redriver_setting(
static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
enum dc_color_depth display_color_depth;
enum engine_id eng_id;
struct ext_hdmi_settings settings = {0};
@@ -1938,12 +1937,12 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
&& (stream->timing.v_addressable == 480);
if (stream->phy_pix_clk == 0)
- stream->phy_pix_clk = stream->timing.pix_clk_khz;
+ stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
if (stream->phy_pix_clk > 340000)
is_over_340mhz = true;
if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
- unsigned short masked_chip_caps = pipe_ctx->stream->sink->link->chip_caps &
+ unsigned short masked_chip_caps = pipe_ctx->stream->link->chip_caps &
EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) {
/* DP159, Retimer settings */
@@ -1964,11 +1963,11 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
dal_ddc_service_write_scdc_data(
- stream->sink->link->ddc,
+ stream->link->ddc,
stream->phy_pix_clk,
stream->timing.flags.LTE_340MCSC_SCRAMBLE);
- memset(&stream->sink->link->cur_link_settings, 0,
+ memset(&stream->link->cur_link_settings, 0,
sizeof(struct dc_link_settings));
display_color_depth = stream->timing.display_color_depth;
@@ -1989,12 +1988,12 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
static void enable_link_lvds(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
if (stream->phy_pix_clk == 0)
- stream->phy_pix_clk = stream->timing.pix_clk_khz;
+ stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
- memset(&stream->sink->link->cur_link_settings, 0,
+ memset(&stream->link->cur_link_settings, 0,
sizeof(struct dc_link_settings));
link->link_enc->funcs->enable_lvds_output(
@@ -2067,7 +2066,7 @@ static bool dp_active_dongle_validate_timing(
const struct dc_crtc_timing *timing,
const struct dpcd_caps *dpcd_caps)
{
- unsigned int required_pix_clk = timing->pix_clk_khz;
+ unsigned int required_pix_clk_100hz = timing->pix_clk_100hz;
const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps;
switch (dpcd_caps->dongle_type) {
@@ -2107,9 +2106,9 @@ static bool dp_active_dongle_validate_timing(
/* Check Color Depth and Pixel Clock */
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- required_pix_clk /= 2;
+ required_pix_clk_100hz /= 2;
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
- required_pix_clk = required_pix_clk * 2 / 3;
+ required_pix_clk_100hz = required_pix_clk_100hz * 2 / 3;
switch (timing->display_color_depth) {
case COLOR_DEPTH_666:
@@ -2119,12 +2118,12 @@ static bool dp_active_dongle_validate_timing(
case COLOR_DEPTH_101010:
if (dongle_caps->dp_hdmi_max_bpc < 10)
return false;
- required_pix_clk = required_pix_clk * 10 / 8;
+ required_pix_clk_100hz = required_pix_clk_100hz * 10 / 8;
break;
case COLOR_DEPTH_121212:
if (dongle_caps->dp_hdmi_max_bpc < 12)
return false;
- required_pix_clk = required_pix_clk * 12 / 8;
+ required_pix_clk_100hz = required_pix_clk_100hz * 12 / 8;
break;
case COLOR_DEPTH_141414:
@@ -2134,7 +2133,7 @@ static bool dp_active_dongle_validate_timing(
return false;
}
- if (required_pix_clk > dongle_caps->dp_hdmi_max_pixel_clk)
+ if (required_pix_clk_100hz > (dongle_caps->dp_hdmi_max_pixel_clk * 10))
return false;
return true;
@@ -2145,7 +2144,7 @@ enum dc_status dc_link_validate_mode_timing(
struct dc_link *link,
const struct dc_crtc_timing *timing)
{
- uint32_t max_pix_clk = stream->sink->dongle_max_pix_clk;
+ uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10;
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
/* A hack to avoid failing any modes for EDID override feature on
@@ -2155,7 +2154,7 @@ enum dc_status dc_link_validate_mode_timing(
return DC_OK;
/* Passive Dongle */
- if (0 != max_pix_clk && timing->pix_clk_khz > max_pix_clk)
+ if (0 != max_pix_clk && timing->pix_clk_100hz > max_pix_clk)
return DC_EXCEED_DONGLE_CAP;
/* Active Dongle*/
@@ -2190,8 +2189,7 @@ int dc_link_get_backlight_level(const struct dc_link *link)
bool dc_link_set_backlight_level(const struct dc_link *link,
uint32_t backlight_pwm_u16_16,
- uint32_t frame_ramp,
- const struct dc_stream_state *stream)
+ uint32_t frame_ramp)
{
struct dc *core_dc = link->ctx->dc;
struct abm *abm = core_dc->res_pool->abm;
@@ -2206,10 +2204,6 @@ bool dc_link_set_backlight_level(const struct dc_link *link,
(abm->funcs->set_backlight_level_pwm == NULL))
return false;
- if (stream)
- ((struct dc_stream_state *)stream)->bl_pwm_level =
- backlight_pwm_u16_16;
-
use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
@@ -2219,7 +2213,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link,
for (i = 0; i < MAX_PIPES; i++) {
if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) {
if (core_dc->current_state->res_ctx.
- pipe_ctx[i].stream->sink->link
+ pipe_ctx[i].stream->link
== link)
/* DMCU -1 for all controller id values,
* therefore +1 here
@@ -2279,7 +2273,7 @@ void core_link_resume(struct dc_link *link)
static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream)
{
struct dc_link_settings *link_settings =
- &stream->sink->link->cur_link_settings;
+ &stream->link->cur_link_settings;
uint32_t link_rate_in_mbps =
link_settings->link_rate * LINK_RATE_REF_FREQ_IN_MHZ;
struct fixed31_32 mbps = dc_fixpt_from_int(
@@ -2310,7 +2304,7 @@ static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx)
uint32_t denominator;
bpc = get_color_depth(pipe_ctx->stream_res.pix_clk_params.color_depth);
- kbps = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk * bpc * 3;
+ kbps = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 * bpc * 3;
/*
* margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
@@ -2386,7 +2380,7 @@ static void update_mst_stream_alloc_table(
static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
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};
@@ -2466,7 +2460,7 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx)
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->sink->link;
+ struct dc_link *link = stream->link;
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};
@@ -2551,8 +2545,8 @@ void core_link_enable_stream(
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL) {
- stream->sink->link->link_enc->funcs->setup(
- stream->sink->link->link_enc,
+ stream->link->link_enc->funcs->setup(
+ stream->link->link_enc,
pipe_ctx->stream->signal);
pipe_ctx->stream_res.stream_enc->funcs->setup_stereo_sync(
pipe_ctx->stream_res.stream_enc,
@@ -2586,13 +2580,23 @@ void core_link_enable_stream(
&stream->timing);
if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ bool apply_edp_fast_boot_optimization =
+ pipe_ctx->stream->apply_edp_fast_boot_optimization;
+
+ pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
+
resource_build_info_frame(pipe_ctx);
core_dc->hwss.update_info_frame(pipe_ctx);
+ /* Do not touch link on seamless boot optimization. */
+ if (pipe_ctx->stream->apply_seamless_boot_optimization) {
+ pipe_ctx->stream->dpms_off = false;
+ return;
+ }
+
/* eDP lit up by bios already, no need to enable again. */
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
- pipe_ctx->stream->apply_edp_fast_boot_optimization) {
- pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
+ apply_edp_fast_boot_optimization) {
pipe_ctx->stream->dpms_off = false;
return;
}
@@ -2604,7 +2608,7 @@ void core_link_enable_stream(
if (status != DC_OK) {
DC_LOG_WARNING("enabling link %u failed: %d\n",
- pipe_ctx->stream->sink->link->link_index,
+ pipe_ctx->stream->link->link_index,
status);
/* Abort stream enable *unless* the failure was due to
@@ -2619,6 +2623,8 @@ void core_link_enable_stream(
}
}
+ stream->link->link_status.link_active = true;
+
core_dc->hwss.enable_audio_stream(pipe_ctx);
/* turn off otg test pattern if enable */
@@ -2633,15 +2639,10 @@ void core_link_enable_stream(
allocate_mst_payload(pipe_ctx);
core_dc->hwss.unblank_stream(pipe_ctx,
- &pipe_ctx->stream->sink->link->cur_link_settings);
+ &pipe_ctx->stream->link->cur_link_settings);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
enable_stream_features(pipe_ctx);
-
- dc_link_set_backlight_level(pipe_ctx->stream->sink->link,
- pipe_ctx->stream->bl_pwm_level,
- 0,
- pipe_ctx->stream);
}
}
@@ -2657,7 +2658,9 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
core_dc->hwss.disable_stream(pipe_ctx, option);
- disable_link(pipe_ctx->stream->sink->link, pipe_ctx->stream->signal);
+ disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
+
+ pipe_ctx->stream->link->link_status.link_active = false;
}
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
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 506a97e16956..b7ee63cd8dc7 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
@@ -33,7 +33,7 @@
#include "include/vector.h"
#include "core_types.h"
#include "dc_link_ddc.h"
-#include "aux_engine.h"
+#include "dce/dce_aux.h"
#define AUX_POWER_UP_WA_DELAY 500
#define I2C_OVER_AUX_DEFER_WA_DELAY 70
@@ -42,7 +42,6 @@
#define CV_SMART_DONGLE_ADDRESS 0x20
/* DVI-HDMI dongle slave address for retrieving dongle signature*/
#define DVI_HDMI_DONGLE_ADDRESS 0x68
-static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G";
struct dvi_hdmi_dongle_signature_data {
int8_t vendor[3];/* "AMD" */
uint8_t version[2];
@@ -165,43 +164,6 @@ static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p)
}
-static struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count)
-{
- struct aux_payloads *payloads;
-
- payloads = kzalloc(sizeof(struct aux_payloads), GFP_KERNEL);
-
- if (!payloads)
- return NULL;
-
- if (dal_vector_construct(
- &payloads->payloads, ctx, count, sizeof(struct aux_payload)))
- return payloads;
-
- kfree(payloads);
- return NULL;
-}
-
-static struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p)
-{
- return (struct aux_payload *)p->payloads.container;
-}
-
-static uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p)
-{
- return p->payloads.count;
-}
-
-static void dal_ddc_aux_payloads_destroy(struct aux_payloads **p)
-{
- if (!p || !*p)
- return;
-
- dal_vector_destruct(&(*p)->payloads);
- kfree(*p);
- *p = NULL;
-}
-
#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
void dal_ddc_i2c_payloads_add(
@@ -225,27 +187,6 @@ void dal_ddc_i2c_payloads_add(
}
-void dal_ddc_aux_payloads_add(
- struct aux_payloads *payloads,
- uint32_t address,
- uint32_t len,
- uint8_t *data,
- bool write)
-{
- uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE;
- uint32_t pos;
-
- for (pos = 0; pos < len; pos += payload_size) {
- struct aux_payload payload = {
- .i2c_over_aux = true,
- .write = write,
- .address = address,
- .length = DDC_MIN(payload_size, len - pos),
- .data = data + pos };
- dal_vector_append(&payloads->payloads, &payload);
- }
-}
-
static void construct(
struct ddc_service *ddc_service,
struct ddc_service_init_data *init_data)
@@ -574,32 +515,34 @@ bool dal_ddc_service_query_ddc_data(
/*TODO: len of payload data for i2c and aux is uint8!!!!,
* but we want to read 256 over i2c!!!!*/
if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
-
- struct aux_payloads *payloads =
- dal_ddc_aux_payloads_create(ddc->ctx, payloads_num);
-
- struct aux_command command = {
- .payloads = dal_ddc_aux_payloads_get(payloads),
- .number_of_payloads = 0,
+ struct aux_payload write_payload = {
+ .i2c_over_aux = true,
+ .write = true,
+ .mot = true,
+ .address = address,
+ .length = write_size,
+ .data = write_buf,
+ .reply = NULL,
.defer_delay = get_defer_delay(ddc),
- .max_defer_write_retry = 0 };
+ };
- dal_ddc_aux_payloads_add(
- payloads, address, write_size, write_buf, true);
-
- dal_ddc_aux_payloads_add(
- payloads, address, read_size, read_buf, false);
-
- command.number_of_payloads =
- dal_ddc_aux_payloads_get_count(payloads);
+ struct aux_payload read_payload = {
+ .i2c_over_aux = true,
+ .write = false,
+ .mot = false,
+ .address = address,
+ .length = read_size,
+ .data = read_buf,
+ .reply = NULL,
+ .defer_delay = get_defer_delay(ddc),
+ };
- ret = dal_i2caux_submit_aux_command(
- ddc->ctx->i2caux,
- ddc->ddc_pin,
- &command);
+ ret = dc_link_aux_transfer_with_retries(ddc, &write_payload);
- dal_ddc_aux_payloads_destroy(&payloads);
+ if (!ret)
+ return false;
+ ret = dc_link_aux_transfer_with_retries(ddc, &read_payload);
} else {
struct i2c_payloads *payloads =
dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num);
@@ -631,56 +574,15 @@ bool dal_ddc_service_query_ddc_data(
}
int dc_link_aux_transfer(struct ddc_service *ddc,
- unsigned int address,
- uint8_t *reply,
- void *buffer,
- unsigned int size,
- enum aux_transaction_type type,
- enum i2caux_transaction_action action)
+ struct aux_payload *payload)
{
- struct ddc *ddc_pin = ddc->ddc_pin;
- struct aux_engine *aux_engine;
- enum aux_channel_operation_result operation_result;
- 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];
- aux_engine->funcs->acquire(aux_engine, ddc_pin);
-
- aux_req.type = type;
- aux_req.action = action;
-
- aux_req.address = address;
- aux_req.delay = 0;
- aux_req.length = size;
- aux_req.data = buffer;
-
- aux_engine->funcs->submit_channel_request(aux_engine, &aux_req);
- operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- res = aux_engine->funcs->read_channel_reply(aux_engine, size,
- buffer, reply,
- &status);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- res = 0;
- break;
- case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- res = -1;
- break;
- }
- aux_engine->funcs->release_engine(aux_engine);
- return res;
+ return dce_aux_transfer(ddc, payload);
+}
+
+bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *payload)
+{
+ return dce_aux_transfer_with_retries(ddc, payload);
}
/*test only function*/
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 0caacb60b02f..09d301216076 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
@@ -49,6 +49,8 @@ static void wait_for_training_aux_rd_interval(
{
union training_aux_rd_interval training_rd_interval;
+ 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
@@ -117,6 +119,13 @@ static void dpcd_set_link_settings(
core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
&downspread.raw, sizeof(downspread));
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
+ (link->dpcd_caps.link_rate_set >= 1 &&
+ link->dpcd_caps.link_rate_set <= 8)) {
+ core_link_write_dpcd(link, DP_LINK_RATE_SET,
+ &link->dpcd_caps.link_rate_set, 1);
+ }
+
DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n",
__func__,
DP_LINK_BW_SET,
@@ -1542,7 +1551,7 @@ static uint32_t bandwidth_in_kbps_from_timing(
ASSERT(bits_per_channel != 0);
- kbps = timing->pix_clk_khz;
+ kbps = timing->pix_clk_100hz / 10;
kbps *= bits_per_channel;
if (timing->flags.Y_ONLY != 1) {
@@ -1584,7 +1593,7 @@ bool dp_validate_mode_timing(
const struct dc_link_settings *link_setting;
/*always DP fail safe mode*/
- if (timing->pix_clk_khz == (uint32_t) 25175 &&
+ if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 &&
timing->h_addressable == (uint32_t) 640 &&
timing->v_addressable == (uint32_t) 480)
return true;
@@ -1634,7 +1643,7 @@ void decide_link_settings(struct dc_stream_state *stream,
req_bw = bandwidth_in_kbps_from_timing(&stream->timing);
- link = stream->sink->link;
+ link = stream->link;
/* if preferred is specified through AMDDP, use it, if it's enough
* to drive the mode
@@ -1656,7 +1665,7 @@ void decide_link_settings(struct dc_stream_state *stream,
}
/* EDP use the link cap setting */
- if (stream->sink->sink_signal == SIGNAL_TYPE_EDP) {
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
*link_setting = link->verified_link_cap;
return;
}
@@ -2002,11 +2011,7 @@ static void handle_automated_test(struct dc_link *link)
dp_test_send_phy_test_pattern(link);
test_response.bits.ACK = 1;
}
- if (!test_request.raw)
- /* no requests, revert all test signals
- * TODO: revert all test signals
- */
- test_response.bits.ACK = 1;
+
/* send request acknowledgment */
if (test_response.bits.ACK)
core_link_write_dpcd(
@@ -2493,13 +2498,72 @@ bool detect_dp_sink_caps(struct dc_link *link)
/* TODO save sink caps in link->sink */
}
+enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
+{
+ enum dc_link_rate link_rate;
+ // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
+ switch (link_rate_in_khz) {
+ case 1620000:
+ link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane
+ break;
+ case 2160000:
+ link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane
+ break;
+ case 2430000:
+ link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane
+ break;
+ case 2700000:
+ link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane
+ break;
+ case 3240000:
+ link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane
+ break;
+ case 4320000:
+ link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane
+ break;
+ case 5400000:
+ link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane
+ break;
+ case 8100000:
+ link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane
+ break;
+ default:
+ link_rate = LINK_RATE_UNKNOWN;
+ break;
+ }
+ return link_rate;
+}
+
void detect_edp_sink_caps(struct dc_link *link)
{
- retrieve_link_cap(link);
+ uint8_t supported_link_rates[16] = {0};
+ uint32_t entry;
+ uint32_t link_rate_in_khz;
+ enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
- if (link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)
- link->reported_link_cap.link_rate = LINK_RATE_HIGH2;
+ retrieve_link_cap(link);
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
+ // Read DPCD 00010h - 0001Fh 16 bytes at one shot
+ core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
+ supported_link_rates, sizeof(supported_link_rates));
+
+ link->dpcd_caps.link_rate_set = 0;
+ for (entry = 0; entry < 16; entry += 2) {
+ // DPCD register reports per-lane link rate = 16-bit link rate capability
+ // value X 200 kHz. Need multipler to find link rate in kHz.
+ link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
+ supported_link_rates[entry]) * 200;
+
+ if (link_rate_in_khz != 0) {
+ link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
+ if (link->reported_link_cap.link_rate < link_rate) {
+ link->reported_link_cap.link_rate = link_rate;
+ link->dpcd_caps.link_rate_set = entry;
+ }
+ }
+ }
+ }
link->verified_link_cap = link->reported_link_cap;
}
@@ -2621,7 +2685,7 @@ bool dc_link_dp_set_test_pattern(
memset(&training_pattern, 0, sizeof(training_pattern));
for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream->sink->link == link) {
+ if (pipes[i].stream->link == link) {
pipe_ctx = &pipes[i];
break;
}
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
index 0065ec7d5330..f7f7515f65f4 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -70,13 +70,12 @@ void dp_enable_link_phy(
*/
for (i = 0; i < MAX_PIPES; i++) {
if (pipes[i].stream != NULL &&
- pipes[i].stream->sink != NULL &&
- pipes[i].stream->sink->link == link) {
+ 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 =
- pipes[i].stream->timing.pix_clk_khz;
+ 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,
@@ -120,6 +119,10 @@ bool edp_receiver_ready_T9(struct dc_link *link)
break;
udelay(100); //MAx T9
} while (++tries < 50);
+
+ if (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);
+
return result;
}
bool edp_receiver_ready_T7(struct dc_link *link)
@@ -279,10 +282,8 @@ void dp_retrain_link_dp_test(struct dc_link *link,
for (i = 0; i < MAX_PIPES; i++) {
if (pipes[i].stream != NULL &&
!pipes[i].top_pipe &&
- pipes[i].stream->sink != NULL &&
- pipes[i].stream->sink->link != NULL &&
- pipes[i].stream_res.stream_enc != NULL &&
- pipes[i].stream->sink->link == link) {
+ pipes[i].stream->link != NULL &&
+ pipes[i].stream_res.stream_enc != NULL) {
udelay(100);
pipes[i].stream_res.stream_enc->funcs->dp_blank(
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 76137df74a53..349ab8017776 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -355,8 +355,8 @@ bool resource_are_streams_timing_synchronizable(
!= stream2->timing.v_addressable)
return false;
- if (stream1->timing.pix_clk_khz
- != stream2->timing.pix_clk_khz)
+ if (stream1->timing.pix_clk_100hz
+ != stream2->timing.pix_clk_100hz)
return false;
if (stream1->clamping.c_depth != stream2->clamping.c_depth)
@@ -1559,7 +1559,7 @@ static struct stream_encoder *find_first_free_match_stream_enc_for_link(
{
int i;
int j = -1;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
for (i = 0; i < pool->stream_enc_count; i++) {
if (!res_ctx->is_stream_enc_acquired[i] &&
@@ -1748,7 +1748,7 @@ static struct dc_stream_state *find_pll_sharable_stream(
if (resource_are_streams_timing_synchronizable(
stream_needs_pll, stream_has_pll)
&& !dc_is_dp_signal(stream_has_pll->signal)
- && stream_has_pll->sink->link->connector_signal
+ && stream_has_pll->link->connector_signal
!= SIGNAL_TYPE_VIRTUAL)
return stream_has_pll;
@@ -1759,7 +1759,7 @@ static struct dc_stream_state *find_pll_sharable_stream(
static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
{
- uint32_t pix_clk = timing->pix_clk_khz;
+ uint32_t pix_clk = timing->pix_clk_100hz;
uint32_t normalized_pix_clk = pix_clk;
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
@@ -1791,15 +1791,60 @@ static void calculate_phy_pix_clks(struct dc_stream_state *stream)
/* update actual pixel clock on all streams */
if (dc_is_hdmi_signal(stream->signal))
stream->phy_pix_clk = get_norm_pix_clk(
- &stream->timing);
+ &stream->timing) / 10;
else
stream->phy_pix_clk =
- stream->timing.pix_clk_khz;
+ stream->timing.pix_clk_100hz / 10;
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
stream->phy_pix_clk *= 2;
}
+static int acquire_resource_from_hw_enabled_state(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct dc_stream_state *stream)
+{
+ struct dc_link *link = stream->link;
+ unsigned int inst;
+
+ /* Check for enabled DIG to identify enabled display */
+ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ return -1;
+
+ /* Check for which front end is used by this encoder.
+ * Note the inst is 1 indexed, where 0 is undefined.
+ * Note that DIG_FE can source from different OTG but our
+ * current implementation always map 1-to-1, so this code makes
+ * the same assumption and doesn't check OTG source.
+ */
+ inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+
+ /* Instance should be within the range of the pool */
+ if (inst >= pool->pipe_count)
+ return -1;
+
+ if (!res_ctx->pipe_ctx[inst].stream) {
+ struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst];
+
+ pipe_ctx->stream_res.tg = pool->timing_generators[inst];
+ pipe_ctx->plane_res.mi = pool->mis[inst];
+ pipe_ctx->plane_res.hubp = pool->hubps[inst];
+ pipe_ctx->plane_res.ipp = pool->ipps[inst];
+ pipe_ctx->plane_res.xfm = pool->transforms[inst];
+ pipe_ctx->plane_res.dpp = pool->dpps[inst];
+ pipe_ctx->stream_res.opp = pool->opps[inst];
+ if (pool->dpps[inst])
+ pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst;
+ pipe_ctx->pipe_idx = inst;
+
+ pipe_ctx->stream = stream;
+ return inst;
+ }
+
+ return -1;
+}
+
enum dc_status resource_map_pool_resources(
const struct dc *dc,
struct dc_state *context,
@@ -1824,8 +1869,15 @@ enum dc_status resource_map_pool_resources(
calculate_phy_pix_clks(stream);
- /* acquire new resources */
- pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
+ if (stream->apply_seamless_boot_optimization)
+ pipe_idx = acquire_resource_from_hw_enabled_state(
+ &context->res_ctx,
+ pool,
+ stream);
+
+ if (pipe_idx < 0)
+ /* acquire new resources */
+ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
#ifdef CONFIG_DRM_AMD_DC_DCN1_0
if (pipe_idx < 0)
@@ -1842,7 +1894,7 @@ enum dc_status resource_map_pool_resources(
&context->res_ctx, pool, stream);
if (!pipe_ctx->stream_res.stream_enc)
- return DC_NO_STREAM_ENG_RESOURCE;
+ return DC_NO_STREAM_ENC_RESOURCE;
update_stream_engine_usage(
&context->res_ctx, pool,
@@ -1850,7 +1902,7 @@ enum dc_status resource_map_pool_resources(
true);
/* TODO: Add check if ASIC support and EDID audio */
- if (!stream->sink->converter_disable_audio &&
+ if (!stream->converter_disable_audio &&
dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
stream->audio_info.mode_count) {
pipe_ctx->stream_res.audio = find_first_free_audio(
@@ -2112,7 +2164,7 @@ static void set_avi_info_frame(
itc = true;
itc_value = 1;
- support = stream->sink->edid_caps.content_support;
+ support = stream->content_support;
if (itc) {
if (!support.bits.valid_content_type) {
@@ -2151,8 +2203,8 @@ static void set_avi_info_frame(
/* TODO : We should handle YCC quantization */
/* but we do not have matrix calculation */
- if (stream->sink->edid_caps.qs_bit == 1 &&
- stream->sink->edid_caps.qy_bit == 1) {
+ if (stream->qs_bit == 1 &&
+ stream->qy_bit == 1) {
if (color_space == COLOR_SPACE_SRGB ||
color_space == COLOR_SPACE_2020_RGB_FULLRANGE) {
hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE;
@@ -2596,7 +2648,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
{
struct dc *core_dc = dc;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
struct timing_generator *tg = core_dc->res_pool->timing_generators[0];
enum dc_status res = DC_OK;
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 66e5c4623a49..996298c35f42 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -35,20 +35,17 @@
/*******************************************************************************
* Private functions
******************************************************************************/
-void update_stream_signal(struct dc_stream_state *stream)
+void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink)
{
-
- struct dc_sink *dc_sink = stream->sink;
-
- if (dc_sink->sink_signal == SIGNAL_TYPE_NONE)
- stream->signal = stream->sink->link->connector_signal;
+ if (sink->sink_signal == SIGNAL_TYPE_NONE)
+ stream->signal = stream->link->connector_signal;
else
- stream->signal = dc_sink->sink_signal;
+ stream->signal = sink->sink_signal;
if (dc_is_dvi_signal(stream->signal)) {
if (stream->ctx->dc->caps.dual_link_dvi &&
- stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK &&
- stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
+ (stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK &&
+ sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;
else
stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
@@ -61,10 +58,15 @@ static void construct(struct dc_stream_state *stream,
uint32_t i = 0;
stream->sink = dc_sink_data;
- stream->ctx = stream->sink->ctx;
-
dc_sink_retain(dc_sink_data);
+ stream->ctx = dc_sink_data->ctx;
+ stream->link = dc_sink_data->link;
+ stream->sink_patches = dc_sink_data->edid_caps.panel_patch;
+ stream->converter_disable_audio = dc_sink_data->converter_disable_audio;
+ stream->qs_bit = dc_sink_data->edid_caps.qs_bit;
+ stream->qy_bit = dc_sink_data->edid_caps.qy_bit;
+
/* Copy audio modes */
/* TODO - Remove this translation */
for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++)
@@ -100,11 +102,14 @@ static void construct(struct dc_stream_state *stream,
/* EDID CAP translation for HDMI 2.0 */
stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
- update_stream_signal(stream);
+ update_stream_signal(stream, dc_sink_data);
stream->out_transfer_func = dc_create_transfer_func();
stream->out_transfer_func->type = TF_TYPE_BYPASS;
stream->out_transfer_func->ctx = stream->ctx;
+
+ stream->stream_id = stream->ctx->dc_stream_id_count;
+ stream->ctx->dc_stream_id_count++;
}
static void destruct(struct dc_stream_state *stream)
@@ -155,21 +160,43 @@ struct dc_stream_state *dc_create_stream_for_sink(
return stream;
}
-struct dc_stream_status *dc_stream_get_status(
+/**
+ * dc_stream_get_status_from_state - Get stream status from given dc state
+ * @state: DC state to find the stream status in
+ * @stream: The stream to get the stream status for
+ *
+ * The given stream is expected to exist in the given dc state. Otherwise, NULL
+ * will be returned.
+ */
+struct dc_stream_status *dc_stream_get_status_from_state(
+ struct dc_state *state,
struct dc_stream_state *stream)
{
uint8_t i;
- struct dc *dc = stream->ctx->dc;
- for (i = 0; i < dc->current_state->stream_count; i++) {
- if (stream == dc->current_state->streams[i])
- return &dc->current_state->stream_status[i];
+ for (i = 0; i < state->stream_count; i++) {
+ if (stream == state->streams[i])
+ return &state->stream_status[i];
}
return NULL;
}
/**
+ * dc_stream_get_status() - Get current stream status of the given stream state
+ * @stream: The stream to get the stream status for.
+ *
+ * The given stream is expected to exist in dc->current_state. Otherwise, NULL
+ * will be returned.
+ */
+struct dc_stream_status *dc_stream_get_status(
+ struct dc_stream_state *stream)
+{
+ struct dc *dc = stream->ctx->dc;
+ return dc_stream_get_status_from_state(dc->current_state, stream);
+}
+
+/**
* dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address
*/
bool dc_stream_set_cursor_attributes(
@@ -334,16 +361,12 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
stream->output_color_space);
DC_LOG_DC(
"\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n",
- stream->timing.pix_clk_khz,
+ stream->timing.pix_clk_100hz / 10,
stream->timing.h_total,
stream->timing.v_total,
stream->timing.pixel_encoding,
stream->timing.display_color_depth);
DC_LOG_DC(
- "\tsink name: %s, serial: %d\n",
- stream->sink->edid_caps.display_name,
- stream->sink->edid_caps.serial_number);
- DC_LOG_DC(
"\tlink: %d\n",
- stream->sink->link->link_index);
+ stream->link->link_index);
}
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 c60c9b4c3075..ee6bd50f60b8 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
@@ -40,11 +40,14 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state
plane_state->ctx = ctx;
plane_state->gamma_correction = dc_create_gamma();
- plane_state->gamma_correction->is_identity = true;
+ if (plane_state->gamma_correction != NULL)
+ plane_state->gamma_correction->is_identity = true;
plane_state->in_transfer_func = dc_create_transfer_func();
- plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
- plane_state->in_transfer_func->ctx = ctx;
+ if (plane_state->in_transfer_func != NULL) {
+ plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
+ plane_state->in_transfer_func->ctx = ctx;
+ }
}
static void destruct(struct dc_plane_state *plane_state)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c
new file mode 100644
index 000000000000..6ce87b682a32
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "vm_helper.h"
+
+static void mark_vmid_used(struct vm_helper *vm_helper, unsigned int pos, uint8_t hubp_idx)
+{
+ struct vmid_usage vmids = vm_helper->hubp_vmid_usage[hubp_idx];
+
+ vmids.vmid_usage[0] = vmids.vmid_usage[1];
+ vmids.vmid_usage[1] = 1 << pos;
+}
+
+static void add_ptb_to_table(struct vm_helper *vm_helper, unsigned int vmid, uint64_t ptb)
+{
+ vm_helper->ptb_assigned_to_vmid[vmid] = ptb;
+ vm_helper->num_vmids_available--;
+}
+
+static void clear_entry_from_vmid_table(struct vm_helper *vm_helper, unsigned int vmid)
+{
+ vm_helper->ptb_assigned_to_vmid[vmid] = 0;
+ vm_helper->num_vmids_available++;
+}
+
+static void evict_vmids(struct vm_helper *vm_helper)
+{
+ int i;
+ uint16_t ord = 0;
+
+ for (i = 0; i < vm_helper->num_vmid; i++)
+ ord |= vm_helper->hubp_vmid_usage[i].vmid_usage[0] | vm_helper->hubp_vmid_usage[i].vmid_usage[1];
+
+ // At this point any positions with value 0 are unused vmids, evict them
+ for (i = 1; i < vm_helper->num_vmid; i++) {
+ if (ord & (1u << i))
+ clear_entry_from_vmid_table(vm_helper, i);
+ }
+}
+
+// Return value of -1 indicates vmid table unitialized or ptb dne in the table
+static int get_existing_vmid_for_ptb(struct vm_helper *vm_helper, uint64_t ptb)
+{
+ int i;
+
+ for (i = 0; i < vm_helper->num_vmid; i++) {
+ if (vm_helper->ptb_assigned_to_vmid[i] == ptb)
+ return i;
+ }
+
+ return -1;
+}
+
+// Expected to be called only when there's an available vmid
+static int get_next_available_vmid(struct vm_helper *vm_helper)
+{
+ int i;
+
+ for (i = 1; i < vm_helper->num_vmid; i++) {
+ if (vm_helper->ptb_assigned_to_vmid[i] == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+uint8_t get_vmid_for_ptb(struct vm_helper *vm_helper, int64_t ptb, uint8_t hubp_idx)
+{
+ unsigned int vmid = 0;
+ int vmid_exists = -1;
+
+ // Physical address gets vmid 0
+ if (ptb == 0)
+ return 0;
+
+ vmid_exists = get_existing_vmid_for_ptb(vm_helper, ptb);
+
+ if (vmid_exists != -1) {
+ mark_vmid_used(vm_helper, vmid_exists, hubp_idx);
+ vmid = vmid_exists;
+ } else {
+ if (vm_helper->num_vmids_available == 0)
+ evict_vmids(vm_helper);
+
+ vmid = get_next_available_vmid(vm_helper);
+ mark_vmid_used(vm_helper, vmid, hubp_idx);
+ add_ptb_to_table(vm_helper, vmid, ptb);
+ }
+
+ return vmid;
+}
+
+void init_vm_helper(struct vm_helper *vm_helper, unsigned int num_vmid, unsigned int num_hubp)
+{
+ vm_helper->num_vmid = num_vmid;
+ vm_helper->num_hubp = num_hubp;
+ vm_helper->num_vmids_available = num_vmid - 1;
+
+ memset(vm_helper->hubp_vmid_usage, 0, sizeof(vm_helper->hubp_vmid_usage[0]) * MAX_HUBP);
+ memset(vm_helper->ptb_assigned_to_vmid, 0, sizeof(vm_helper->ptb_assigned_to_vmid[0]) * MAX_VMID);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 4b5bbb13ce7f..1a7fd6aa77eb 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -39,7 +39,7 @@
#include "inc/hw/dmcu.h"
#include "dml/display_mode_lib.h"
-#define DC_VER "3.2.08"
+#define DC_VER "3.2.17"
#define MAX_SURFACES 3
#define MAX_STREAMS 6
@@ -255,6 +255,8 @@ struct dc_debug_options {
bool scl_reset_length10;
bool hdmi20_disable;
bool skip_detection_link_training;
+ unsigned int force_odm_combine; //bit vector based on otg inst
+ unsigned int force_fclk_khz;
};
struct dc_debug_data {
@@ -263,7 +265,6 @@ struct dc_debug_data {
uint32_t auxErrorCount;
};
-
struct dc_state;
struct resource_pool;
struct dce_hwseq;
@@ -339,8 +340,13 @@ struct dc_init_data {
uint32_t log_mask;
};
-struct dc *dc_create(const struct dc_init_data *init_params);
+struct dc_callback_init {
+ uint8_t reserved;
+};
+struct dc *dc_create(const struct dc_init_data *init_params);
+void dc_init_callbacks(struct dc *dc,
+ const struct dc_callback_init *init_params);
void dc_destroy(struct dc **dc);
/*******************************************************************************
@@ -440,6 +446,7 @@ union surface_update_flags {
uint32_t coeff_reduction_change:1;
uint32_t output_tf_change:1;
uint32_t pixel_format_change:1;
+ uint32_t plane_size_change:1;
/* Full updates */
uint32_t new_plane:1;
@@ -587,6 +594,10 @@ struct dc_validation_set {
uint8_t plane_count;
};
+bool dc_validate_seamless_boot_timing(struct dc *dc,
+ const struct dc_sink *sink,
+ struct dc_crtc_timing *crtc_timing);
+
enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state);
void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info);
@@ -652,6 +663,7 @@ struct dpcd_caps {
int8_t branch_dev_name[6];
int8_t branch_hw_revision;
int8_t branch_fw_revision[2];
+ uint8_t link_rate_set;
bool allow_invalid_MSA_timing_param;
bool panel_mode_edp;
@@ -742,6 +754,9 @@ void dc_set_power_state(
struct dc *dc,
enum dc_acpi_cm_power_state power_state);
void dc_resume(struct dc *dc);
+unsigned int dc_get_current_backlight_pwm(struct dc *dc);
+unsigned int dc_get_target_backlight_pwm(struct dc *dc);
+
bool dc_is_dmcu_initialized(struct dc *dc);
#endif /* DC_INTERFACE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
index a8b3cedf9431..78c3b300ec45 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
@@ -86,10 +86,6 @@ struct dc_vbios_funcs {
bool (*is_accelerated_mode)(
struct dc_bios *bios);
- bool (*is_active_display)(
- struct dc_bios *bios,
- enum signal_type signal,
- const struct connector_device_tag_info *device_tag);
void (*set_scratch_critical_state)(
struct dc_bios *bios,
bool state);
@@ -125,10 +121,6 @@ struct dc_vbios_funcs {
enum bp_result (*program_crtc_timing)(
struct dc_bios *bios,
struct bp_hw_crtc_timing_parameters *bp_params);
-
- enum bp_result (*crtc_source_select)(
- struct dc_bios *bios,
- struct bp_crtc_source_select *bp_params);
enum bp_result (*program_display_engine_pll)(
struct dc_bios *bios,
struct bp_pixel_clock_parameters *bp_params);
@@ -145,7 +137,6 @@ struct dc_vbios_funcs {
};
struct bios_registers {
- uint32_t BIOS_SCRATCH_0;
uint32_t BIOS_SCRATCH_3;
uint32_t BIOS_SCRATCH_6;
};
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 da93ab43f2d8..d4eab33c453b 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -46,11 +46,14 @@ enum dc_lane_count {
*/
enum dc_link_rate {
LINK_RATE_UNKNOWN = 0,
- LINK_RATE_LOW = 0x06,
- LINK_RATE_HIGH = 0x0A,
- LINK_RATE_RBR2 = 0x0C,
- LINK_RATE_HIGH2 = 0x14,
- LINK_RATE_HIGH3 = 0x1E
+ LINK_RATE_LOW = 0x06, // Rate_1 (RBR) - 1.62 Gbps/Lane
+ LINK_RATE_RATE_2 = 0x08, // Rate_2 - 2.16 Gbps/Lane
+ LINK_RATE_RATE_3 = 0x09, // Rate_3 - 2.43 Gbps/Lane
+ LINK_RATE_HIGH = 0x0A, // Rate_4 (HBR) - 2.70 Gbps/Lane
+ 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
+ LINK_RATE_HIGH3 = 0x1E // Rate_8 (HBR3)- 8.10 Gbps/Lane
};
enum dc_link_spread {
diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c
index 4842d2378bbf..597d38393379 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c
@@ -29,31 +29,59 @@
#include "dm_services.h"
#include <stdarg.h>
+struct dc_reg_value_masks {
+ uint32_t value;
+ uint32_t mask;
+};
+
+struct dc_reg_sequence {
+ uint32_t addr;
+ struct dc_reg_value_masks value_masks;
+};
+
+static inline void set_reg_field_value_masks(
+ struct dc_reg_value_masks *field_value_mask,
+ uint32_t value,
+ uint32_t mask,
+ uint8_t shift)
+{
+ ASSERT(mask != 0);
+
+ field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift));
+ field_value_mask->mask = field_value_mask->mask | mask;
+}
+
uint32_t generic_reg_update_ex(const struct dc_context *ctx,
uint32_t addr, uint32_t reg_val, int n,
uint8_t shift1, uint32_t mask1, uint32_t field_value1,
...)
{
+ struct dc_reg_value_masks field_value_mask = {0};
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);
+ /* gather all bits value/mask getting updated in this register */
+ set_reg_field_value_masks(&field_value_mask,
+ 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);
+ set_reg_field_value_masks(&field_value_mask,
+ field_value, mask, shift);
i++;
}
-
- dm_write_reg(ctx, addr, reg_val);
va_end(ap);
+
+ /* mmio write directly */
+ reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
+ dm_write_reg(ctx, addr, reg_val);
return reg_val;
}
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 e72fce4eca65..da55d623647a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -97,6 +97,8 @@ struct dc_plane_address {
union large_integer chroma_dcc_const_color;
} video_progressive;
};
+
+ union large_integer page_table_base;
};
struct dc_size {
@@ -730,7 +732,7 @@ struct dc_crtc_timing {
uint32_t v_front_porch;
uint32_t v_sync_width;
- uint32_t pix_clk_khz;
+ uint32_t pix_clk_100hz;
uint32_t vic;
uint32_t hdmi_vic;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 29f19d57ff7a..8fc223defed4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -30,6 +30,7 @@
#include "grph_object_defs.h"
struct dc_link_status {
+ bool link_active;
struct dpcd_caps *dpcd_caps;
};
@@ -110,6 +111,7 @@ struct dc_link {
union ddi_channel_mapping ddi_channel_mapping;
struct connector_device_tag_info device_tag;
struct dpcd_caps dpcd_caps;
+ uint32_t dongle_max_pix_clk;
unsigned short chip_caps;
unsigned int dpcd_sink_count;
enum edp_revision edp_revision;
@@ -124,6 +126,7 @@ struct dc_link {
struct dc_link_status link_status;
struct link_trace link_trace;
+ struct gpio *hpd_gpio;
};
const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link);
@@ -146,8 +149,7 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_
*/
bool dc_link_set_backlight_level(const struct dc_link *dc_link,
uint32_t backlight_pwm_u16_16,
- uint32_t frame_ramp,
- const struct dc_stream_state *stream);
+ uint32_t frame_ramp);
int dc_link_get_backlight_level(const struct dc_link *dc_link);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index be34d638e15d..a798694992b9 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -32,17 +32,18 @@
/*******************************************************************************
* Stream Interfaces
******************************************************************************/
+struct timing_sync_info {
+ int group_id;
+ int group_size;
+ bool master;
+};
struct dc_stream_status {
int primary_otg_inst;
int stream_enc_inst;
int plane_count;
+ struct timing_sync_info timing_sync_info;
struct dc_plane_state *plane_states[MAX_SURFACE_NUM];
-
- /*
- * link this stream passes through
- */
- struct dc_link *link;
};
// TODO: References to this needs to be removed..
@@ -50,8 +51,20 @@ struct freesync_context {
bool dummy;
};
+union vline_config {
+ unsigned int line_number;
+ unsigned long long delta_in_ns;
+};
+
+
struct dc_stream_state {
+ // sink is deprecated, new code should not reference
+ // this pointer
struct dc_sink *sink;
+
+ struct dc_link *link;
+ struct dc_panel_patch sink_patches;
+ union display_content_support content_support;
struct dc_crtc_timing timing;
struct dc_crtc_timing_adjust adjust;
struct dc_info_packet vrr_infopacket;
@@ -80,8 +93,9 @@ struct dc_stream_state {
enum view_3d_format view_format;
bool ignore_msa_timing_param;
-
- unsigned long long periodic_fn_vsync_delta;
+ bool converter_disable_audio;
+ uint8_t qs_bit;
+ uint8_t qy_bit;
/* TODO: custom INFO packets */
/* TODO: ABM info (DMCU) */
@@ -91,7 +105,9 @@ struct dc_stream_state {
/* DMCU info */
unsigned int abm_level;
- unsigned int bl_pwm_level;
+
+ union vline_config periodic_vsync_config;
+ union vline_config enhanced_sync_config;
/* from core_stream struct */
struct dc_context *ctx;
@@ -103,7 +119,8 @@ struct dc_stream_state {
int phy_pix_clk;
enum signal_type signal;
bool dpms_off;
- bool apply_edp_fast_boot_optimization;
+
+ void *dm_stream_context;
struct dc_cursor_attributes cursor_attributes;
struct dc_cursor_position cursor_position;
@@ -117,6 +134,21 @@ struct dc_stream_state {
/* Computed state bits */
bool mode_changed : 1;
+ /* Output from DC when stream state is committed or altered
+ * DC may only access these values during:
+ * dc_commit_state, dc_commit_state_no_check, dc_commit_streams
+ * values may not change outside of those calls
+ */
+ struct {
+ // For interrupt management, some hardware instance
+ // offsets need to be exposed to DM
+ uint8_t otg_offset;
+ } out;
+
+ bool apply_edp_fast_boot_optimization;
+ bool apply_seamless_boot_optimization;
+
+ uint32_t stream_id;
};
struct dc_stream_update {
@@ -126,7 +158,9 @@ struct dc_stream_update {
struct dc_info_packet *hdr_static_metadata;
unsigned int *abm_level;
- unsigned long long *periodic_fn_vsync_delta;
+ union vline_config *periodic_vsync_config;
+ union vline_config *enhanced_sync_config;
+
struct dc_crtc_timing_adjust *adjust;
struct dc_info_packet *vrr_infopacket;
struct dc_info_packet *vsc_infopacket;
@@ -163,7 +197,6 @@ void dc_commit_updates_for_stream(struct dc *dc,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- struct dc_plane_state **plane_states,
struct dc_state *state);
/*
* Log the current stream state.
@@ -256,11 +289,14 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
*/
struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink);
-void update_stream_signal(struct dc_stream_state *stream);
+void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink);
void dc_stream_retain(struct dc_stream_state *dc_stream);
void dc_stream_release(struct dc_stream_state *dc_stream);
+struct dc_stream_status *dc_stream_get_status_from_state(
+ struct dc_state *state,
+ struct dc_stream_state *stream);
struct dc_stream_status *dc_stream_get_status(
struct dc_stream_state *dc_stream);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 0b20ae23f169..da2009a108cf 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -97,8 +97,8 @@ struct dc_context {
struct dc_bios *dc_bios;
bool created_bios;
struct gpio_service *gpio_service;
- struct i2caux *i2caux;
uint32_t dc_sink_id_count;
+ uint32_t dc_stream_id_count;
uint64_t fbc_gpu_addr;
};
@@ -201,6 +201,7 @@ union display_content_support {
struct dc_panel_patch {
unsigned int dppowerup_delay;
unsigned int extra_t12_ms;
+ unsigned int extra_delay_backlight_off;
};
struct dc_edid_caps {
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
index 2a342eae80fd..01e56f1a9f34 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
@@ -314,8 +314,8 @@ static bool dce_abm_immediate_disable(struct abm *abm)
/* setDMCUParam_ABMLevel */
REG_UPDATE_2(MASTER_COMM_CMD_REG,
- MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_LEVEL_SET,
- MASTER_COMM_CMD_REG_BYTE2, MCP_DISABLE_ABM_IMMEDIATELY);
+ MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_PIPE_SET,
+ MASTER_COMM_CMD_REG_BYTE1, MCP_DISABLE_ABM_IMMEDIATELY);
/* notifyDMCUMsg */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
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 aaeb7faac0c4..4febf4ef7240 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
@@ -24,6 +24,7 @@
*/
#include "dm_services.h"
+#include "core_types.h"
#include "dce_aux.h"
#include "dce/dce_11_0_sh_mask.h"
@@ -41,17 +42,17 @@
container_of((ptr), struct aux_engine_dce110, base)
#define FROM_ENGINE(ptr) \
- FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
+ FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
#define FROM_AUX_ENGINE_ENGINE(ptr) \
- container_of((ptr), struct aux_engine, base)
+ container_of((ptr), struct dce_aux, base)
enum {
AUX_INVALID_REPLY_RETRY_COUNTER = 1,
AUX_TIMED_OUT_RETRY_COUNTER = 2,
AUX_DEFER_RETRY_COUNTER = 6
};
static void release_engine(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -66,7 +67,7 @@ static void release_engine(
#define DMCU_CAN_ACCESS_AUX 2
static bool is_engine_available(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -79,7 +80,7 @@ static bool is_engine_available(
return (field != DMCU_CAN_ACCESS_AUX);
}
static bool acquire_engine(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -155,7 +156,7 @@ static bool acquire_engine(
(0xFF & (address))
static void submit_channel_request(
- struct aux_engine *engine,
+ struct dce_aux *engine,
struct aux_request_transaction_data *request)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -247,7 +248,7 @@ static void submit_channel_request(
REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
}
-static int read_channel_reply(struct aux_engine *engine, uint32_t size,
+static int read_channel_reply(struct dce_aux *engine, uint32_t size,
uint8_t *buffer, uint8_t *reply_result,
uint32_t *sw_status)
{
@@ -273,7 +274,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size,
REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
reply_result_32 = reply_result_32 >> 4;
- *reply_result = (uint8_t)reply_result_32;
+ if (reply_result != NULL)
+ *reply_result = (uint8_t)reply_result_32;
if (reply_result_32 == 0) { /* ACK */
uint32_t i = 0;
@@ -299,61 +301,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size,
return 0;
}
-static void process_channel_reply(
- struct aux_engine *engine,
- struct aux_reply_transaction_data *reply)
-{
- int bytes_replied;
- uint8_t reply_result;
- uint32_t sw_status;
-
- bytes_replied = read_channel_reply(engine, reply->length, reply->data,
- &reply_result, &sw_status);
-
- /* in case HPD is LOW, exit AUX transaction */
- if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
- return;
- }
-
- if (bytes_replied < 0) {
- /* Need to handle an error case...
- * Hopefully, upper layer function won't call this function if
- * the number of bytes in the reply was 0, because there was
- * surely an error that was asserted that should have been
- * handled for hot plug case, this could happens
- */
- if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- ASSERT_CRITICAL(false);
- return;
- }
- } else {
-
- switch (reply_result) {
- case 0: /* ACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
- break;
- case 1: /* NACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
- break;
- case 2: /* DEFER */
- reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
- break;
- case 4: /* AUX ACK / I2C NACK */
- reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
- break;
- case 8: /* AUX ACK / I2C DEFER */
- reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
- break;
- default:
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- }
- }
-}
-
static enum aux_channel_operation_result get_channel_status(
- struct aux_engine *engine,
+ struct dce_aux *engine,
uint8_t *returned_bytes)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -414,469 +363,22 @@ static enum aux_channel_operation_result get_channel_status(
return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
}
}
-static void process_read_reply(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->defer_retry_aux = 0;
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else if (ctx->returned_byte < ctx->current_read_length) {
- ctx->current_read_length -= ctx->returned_byte;
-
- ctx->offset += ctx->returned_byte;
-
- ++ctx->invalid_reply_retry_aux_on_ack;
-
- if (ctx->invalid_reply_retry_aux_on_ack >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- }
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->transaction_complete = true;
- ctx->operation_succeeded = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static void process_read_request(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else {
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->buffer;
-
- process_read_reply(engine, ctx);
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here
- */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static bool read_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct read_command_context ctx;
-
- ctx.buffer = request->payload.data;
- ctx.current_read_length = request->payload.length;
- ctx.offset = 0;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.invalid_reply_retry_aux_on_ack = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_READ;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- do {
- memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
-
- ctx.request.data = ctx.buffer + ctx.offset;
- ctx.request.length = ctx.current_read_length;
-
- process_read_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-
-static void process_write_reply(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->operation_succeeded = true;
-
- if (ctx->returned_byte) {
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ctx->current_write_length = 0;
-
- ++ctx->ack_m_retry;
-
- if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else
- udelay(300);
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->defer_retry_aux = 0;
- ctx->ack_m_retry = 0;
- ctx->transaction_complete = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
- ctx->current_write_length = 0;
-
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static void process_write_request(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
-
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->reply_data;
-
- process_write_reply(engine, ctx);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here
- */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static bool write_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct write_command_context ctx;
-
- ctx.mot = middle_of_transaction;
- ctx.buffer = request->payload.data;
- ctx.current_write_length = request->payload.length;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.ack_m_retry = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- ctx.max_defer_retry =
- (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
- engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
-
- do {
- ctx.request.data = ctx.buffer;
- ctx.request.length = ctx.current_write_length;
-
- process_write_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-static bool end_of_transaction_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request)
-{
- struct i2caux_transaction_request dummy_request;
- uint8_t dummy_data;
-
- /* [tcheng] We only need to send the stop (read with MOT = 0)
- * for I2C-over-Aux, not native AUX
- */
-
- if (request->payload.address_space !=
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
- return false;
-
- dummy_request.operation = request->operation;
- dummy_request.payload.address_space = request->payload.address_space;
- dummy_request.payload.address = request->payload.address;
-
- /*
- * Add a dummy byte due to some receiver quirk
- * where one byte is sent along with MOT = 0.
- * Ideally this should be 0.
- */
-
- dummy_request.payload.length = 0;
- dummy_request.payload.data = &dummy_data;
-
- if (request->operation == I2CAUX_TRANSACTION_READ)
- return read_command(engine, &dummy_request, false);
- else
- return write_command(engine, &dummy_request, false);
-
- /* according Syed, it does not need now DoDummyMOT */
-}
-static bool submit_request(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
-
- bool result;
- bool mot_used = true;
-
- switch (request->operation) {
- case I2CAUX_TRANSACTION_READ:
- result = read_command(engine, request, mot_used);
- break;
- case I2CAUX_TRANSACTION_WRITE:
- result = write_command(engine, request, mot_used);
- break;
- default:
- result = false;
- }
-
- /* [tcheng]
- * need to send stop for the last transaction to free up the AUX
- * if the above command fails, this would be the last transaction
- */
-
- if (!middle_of_transaction || !result)
- end_of_transaction_command(engine, request);
-
- /* mask AUX interrupt */
-
- return result;
-}
enum i2caux_engine_type get_engine_type(
- const struct aux_engine *engine)
+ const struct dce_aux *engine)
{
return I2CAUX_ENGINE_TYPE_AUX;
}
static bool acquire(
- struct aux_engine *engine,
+ struct dce_aux *engine,
struct ddc *ddc)
{
enum gpio_result result;
- if (engine->funcs->is_engine_available) {
- /*check whether SW could use the engine*/
- if (!engine->funcs->is_engine_available(engine))
- return false;
- }
+ if (!is_engine_available(engine))
+ return false;
result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
GPIO_DDC_CONFIG_TYPE_MODE_AUX);
@@ -884,7 +386,7 @@ static bool acquire(
if (result != GPIO_RESULT_OK)
return false;
- if (!engine->funcs->acquire_engine(engine)) {
+ if (!acquire_engine(engine)) {
dal_ddc_close(ddc);
return false;
}
@@ -894,21 +396,7 @@ static bool acquire(
return true;
}
-static const struct aux_engine_funcs aux_engine_funcs = {
- .acquire_engine = acquire_engine,
- .submit_channel_request = submit_channel_request,
- .process_channel_reply = process_channel_reply,
- .read_channel_reply = read_channel_reply,
- .get_channel_status = get_channel_status,
- .is_engine_available = is_engine_available,
- .release_engine = release_engine,
- .destroy_engine = dce110_engine_destroy,
- .submit_request = submit_request,
- .get_engine_type = get_engine_type,
- .acquire = acquire,
-};
-
-void dce110_engine_destroy(struct aux_engine **engine)
+void dce110_engine_destroy(struct dce_aux **engine)
{
struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
@@ -917,7 +405,7 @@ void dce110_engine_destroy(struct aux_engine **engine)
*engine = NULL;
}
-struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
+struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
struct dc_context *ctx,
uint32_t inst,
uint32_t timeout_period,
@@ -927,7 +415,6 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng
aux_engine110->base.ctx = ctx;
aux_engine110->base.delay = 0;
aux_engine110->base.max_defer_write_retry = 0;
- aux_engine110->base.funcs = &aux_engine_funcs;
aux_engine110->base.inst = inst;
aux_engine110->timeout_period = timeout_period;
aux_engine110->regs = regs;
@@ -935,3 +422,101 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng
return &aux_engine110->base;
}
+static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
+{
+ if (payload->i2c_over_aux) {
+ if (payload->write) {
+ if (payload->mot)
+ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
+ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
+ }
+ if (payload->mot)
+ return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
+ return I2CAUX_TRANSACTION_ACTION_I2C_READ;
+ }
+ if (payload->write)
+ return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
+ return I2CAUX_TRANSACTION_ACTION_DP_READ;
+}
+
+int dce_aux_transfer(struct ddc_service *ddc,
+ struct aux_payload *payload)
+{
+ struct ddc *ddc_pin = ddc->ddc_pin;
+ struct dce_aux *aux_engine;
+ enum aux_channel_operation_result operation_result;
+ 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];
+ acquire(aux_engine, ddc_pin);
+
+ if (payload->i2c_over_aux)
+ aux_req.type = AUX_TRANSACTION_TYPE_I2C;
+ else
+ aux_req.type = AUX_TRANSACTION_TYPE_DP;
+
+ aux_req.action = i2caux_action_from_payload(payload);
+
+ aux_req.address = payload->address;
+ aux_req.delay = payload->defer_delay * 10;
+ aux_req.length = payload->length;
+ aux_req.data = payload->data;
+
+ submit_channel_request(aux_engine, &aux_req);
+ operation_result = get_channel_status(aux_engine, &returned_bytes);
+
+ switch (operation_result) {
+ case AUX_CHANNEL_OPERATION_SUCCEEDED:
+ res = read_channel_reply(aux_engine, payload->length,
+ payload->data, payload->reply,
+ &status);
+ break;
+ case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
+ res = 0;
+ break;
+ case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
+ case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
+ case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
+ res = -1;
+ break;
+ }
+ release_engine(aux_engine);
+ return res;
+}
+
+#define AUX_RETRY_MAX 7
+
+bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *payload)
+{
+ int i, ret = 0;
+ uint8_t reply;
+ bool payload_reply = true;
+
+ if (!payload->reply) {
+ payload_reply = false;
+ payload->reply = &reply;
+ }
+
+ for (i = 0; i < AUX_RETRY_MAX; i++) {
+ ret = dce_aux_transfer(ddc, payload);
+
+ if (ret >= 0) {
+ if (*payload->reply == 0) {
+ if (!payload_reply)
+ payload->reply = NULL;
+ return true;
+ }
+ }
+
+ udelay(1000);
+ }
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
index f7caab85dc80..d27f22c05e4b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
@@ -25,7 +25,9 @@
#ifndef __DAL_AUX_ENGINE_DCE110_H__
#define __DAL_AUX_ENGINE_DCE110_H__
-#include "aux_engine.h"
+
+#include "i2caux_interface.h"
+#include "inc/hw/aux_engine.h"
#define AUX_COMMON_REG_LIST(id)\
SRI(AUX_CONTROL, DP_AUX, id), \
@@ -75,8 +77,20 @@ enum { /* This is the timeout as defined in DP 1.2a,
*/
SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
};
+
+struct dce_aux {
+ uint32_t inst;
+ struct ddc *ddc;
+ struct dc_context *ctx;
+ /* following values are expressed in milliseconds */
+ uint32_t delay;
+ uint32_t max_defer_write_retry;
+
+ bool acquire_reset;
+};
+
struct aux_engine_dce110 {
- struct aux_engine base;
+ struct dce_aux base;
const struct dce110_aux_registers *regs;
struct {
uint32_t aux_control;
@@ -96,16 +110,22 @@ struct aux_engine_dce110_init_data {
const struct dce110_aux_registers *regs;
};
-struct aux_engine *dce110_aux_engine_construct(
+struct dce_aux *dce110_aux_engine_construct(
struct aux_engine_dce110 *aux_engine110,
struct dc_context *ctx,
uint32_t inst,
uint32_t timeout_period,
const struct dce110_aux_registers *regs);
-void dce110_engine_destroy(struct aux_engine **engine);
+void dce110_engine_destroy(struct dce_aux **engine);
bool dce110_aux_engine_acquire(
- struct aux_engine *aux_engine,
+ struct dce_aux *aux_engine,
struct ddc *ddc);
+
+int dce_aux_transfer(struct ddc_service *ddc,
+ struct aux_payload *cmd);
+
+bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *cmd);
#endif
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 afd287f08bc9..bbe051736a18 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
@@ -194,8 +194,8 @@ static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context)
if (pipe_ctx->top_pipe)
continue;
- if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
- max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+ if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 > max_pix_clk)
+ max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
/* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
* logic for HBR3 still needs Nominal (0.8V) on VDDC rail
@@ -257,7 +257,7 @@ static int dce_set_clock(
clk_mgr_dce->dentist_vco_freq_khz / 64);
/* Prepare to program display clock*/
- pxl_clk_params.target_pixel_clock = requested_clk_khz;
+ pxl_clk_params.target_pixel_clock_100hz = requested_clk_khz * 10;
pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
if (clk_mgr_dce->dfs_bypass_active)
@@ -450,6 +450,42 @@ void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
}
}
+/**
+ * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info
+ * @clk_mgr: clock manager base structure
+ *
+ * Reads from VBIOS the XGMI spread spectrum info and saves it within
+ * the dce clock manager. This operation will overwrite the existing dprefclk
+ * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also
+ * sets the ->xgmi_enabled flag.
+ */
+void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ enum bp_result result;
+ struct spread_spectrum_info info = { { 0 } };
+ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+
+ clk_mgr_dce->xgmi_enabled = false;
+
+ result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI,
+ 0, &info);
+ if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->xgmi_enabled = true;
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider =
+ info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+ }
+}
+
void dce110_fill_display_configs(
const struct dc_state *context,
struct dm_pp_display_configuration *pp_display_cfg)
@@ -483,18 +519,18 @@ void dce110_fill_display_configs(
cfg->src_height = stream->src.height;
cfg->src_width = stream->src.width;
cfg->ddi_channel_mapping =
- stream->sink->link->ddi_channel_mapping.raw;
+ stream->link->ddi_channel_mapping.raw;
cfg->transmitter =
- stream->sink->link->link_enc->transmitter;
+ stream->link->link_enc->transmitter;
cfg->link_settings.lane_count =
- stream->sink->link->cur_link_settings.lane_count;
+ stream->link->cur_link_settings.lane_count;
cfg->link_settings.link_rate =
- stream->sink->link->cur_link_settings.link_rate;
+ stream->link->cur_link_settings.link_rate;
cfg->link_settings.link_spread =
- stream->sink->link->cur_link_settings.link_spread;
+ stream->link->cur_link_settings.link_spread;
cfg->sym_clock = stream->phy_pix_clk;
/* Round v_refresh*/
- cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
+ cfg->v_refresh = stream->timing.pix_clk_100hz * 100;
cfg->v_refresh /= stream->timing.h_total;
cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
/ stream->timing.v_total;
@@ -518,7 +554,7 @@ static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
- stream->timing.v_addressable);
vertical_blank_time = vertical_blank_in_pixels
- * 1000 / stream->timing.pix_clk_khz;
+ * 10000 / stream->timing.pix_clk_100hz;
if (min_vertical_blank_time > vertical_blank_time)
min_vertical_blank_time = vertical_blank_time;
@@ -591,7 +627,15 @@ static void dce11_pplib_apply_display_requirements(
dc,
context->bw.dce.sclk_khz);
- pp_display_cfg->min_dcfclock_khz = pp_display_cfg->min_engine_clock_khz;
+ /*
+ * As workaround for >4x4K lightup set dcfclock to min_engine_clock value.
+ * This is not required for less than 5 displays,
+ * thus don't request decfclk in dc to avoid impact
+ * on power saving.
+ *
+ */
+ pp_display_cfg->min_dcfclock_khz = (context->stream_count > 4)?
+ pp_display_cfg->min_engine_clock_khz : 0;
pp_display_cfg->min_engine_clock_deep_sleep_khz
= context->bw.dce.sclk_deep_sleep_khz;
@@ -612,7 +656,7 @@ static void dce11_pplib_apply_display_requirements(
pp_display_cfg->crtc_index =
pp_display_cfg->disp_configs[0].pipe_idx;
- pp_display_cfg->line_time_in_us = timing->h_total * 1000 / timing->pix_clk_khz;
+ pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz;
}
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
@@ -625,11 +669,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr,
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_power_level_change_request level_change_req;
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
/* get max clock state from PPLIB */
@@ -639,13 +683,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr,
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
}
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
- context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
+ patched_disp_clk = dce_set_clock(clk_mgr, patched_disp_clk);
+ clk_mgr->clks.dispclk_khz = patched_disp_clk;
}
dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static void dce11_update_clocks(struct clk_mgr *clk_mgr,
@@ -676,11 +718,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_power_level_change_request level_change_req;
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
/* get max clock state from PPLIB */
@@ -690,13 +732,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
}
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
- context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
+ patched_disp_clk = dce112_set_clock(clk_mgr, patched_disp_clk);
+ clk_mgr->clks.dispclk_khz = patched_disp_clk;
}
dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static void dce12_update_clocks(struct clk_mgr *clk_mgr,
@@ -706,17 +746,23 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr,
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
- clock_voltage_req.clocks_in_khz = context->bw.dce.dispclk_khz;
- context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ /*
+ * When xGMI is enabled, the display clk needs to be adjusted
+ * with the WAFL link's SS percentage.
+ */
+ if (clk_mgr_dce->xgmi_enabled)
+ patched_disp_clk = clk_mgr_adjust_dp_ref_freq_for_ss(
+ clk_mgr_dce, patched_disp_clk);
+ clock_voltage_req.clocks_in_khz = patched_disp_clk;
+ clk_mgr->clks.dispclk_khz = dce112_set_clock(clk_mgr, patched_disp_clk);
dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
}
@@ -729,8 +775,6 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr,
dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
}
dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static const struct clk_mgr_funcs dce120_funcs = {
@@ -882,6 +926,27 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx)
return &clk_mgr_dce->base;
}
+struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce),
+ GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state, dce120_max_clks_by_state,
+ sizeof(dce120_max_clks_by_state));
+
+ dce_clk_mgr_construct(clk_mgr_dce, ctx, NULL, NULL, NULL);
+
+ clk_mgr_dce->dprefclk_khz = 625000;
+ clk_mgr_dce->base.funcs = &dce120_funcs;
+
+ return &clk_mgr_dce->base;
+}
+
void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr)
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr);
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
index 3bceb31d910d..c8f8c442142a 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
@@ -94,11 +94,37 @@ struct dce_clk_mgr {
* This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
int dfs_bypass_disp_clk;
- /* Flag for Enabled SS on DPREFCLK */
+ /**
+ * @ss_on_dprefclk:
+ *
+ * True if spread spectrum is enabled on the DP ref clock.
+ */
bool ss_on_dprefclk;
- /* DPREFCLK SS percentage (if down-spread enabled) */
+
+ /**
+ * @xgmi_enabled:
+ *
+ * True if xGMI is enabled. On VG20, both audio and display clocks need
+ * to be adjusted with the WAFL link's SS info if xGMI is enabled.
+ */
+ bool xgmi_enabled;
+
+ /**
+ * @dprefclk_ss_percentage:
+ *
+ * DPREFCLK SS percentage (if down-spread enabled).
+ *
+ * Note that if XGMI is enabled, the SS info (percentage and divider)
+ * from the WAFL link is used instead. This is decided during
+ * dce_clk_mgr initialization.
+ */
int dprefclk_ss_percentage;
- /* DPREFCLK SS percentage Divider (100 or 1000) */
+
+ /**
+ * @dprefclk_ss_divider:
+ *
+ * DPREFCLK SS percentage Divider (100 or 1000).
+ */
int dprefclk_ss_divider;
int dprefclk_khz;
@@ -163,6 +189,9 @@ struct clk_mgr *dce112_clk_mgr_create(
struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx);
+struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx);
+void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr);
+
void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr);
int dentist_get_divider_from_did(int did);
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 723ce80ed89c..71d5777de961 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
@@ -108,28 +108,28 @@ static const struct spread_spectrum_data *get_ss_data_entry(
}
/**
-* Function: calculate_fb_and_fractional_fb_divider
-*
-* * DESCRIPTION: Calculates feedback and fractional feedback dividers values
-*
-*PARAMETERS:
-* targetPixelClock Desired frequency in 10 KHz
-* ref_divider Reference divider (already known)
-* postDivider Post Divider (already known)
-* feedback_divider_param Pointer where to store
-* calculated feedback divider value
-* fract_feedback_divider_param Pointer where to store
-* calculated fract feedback divider value
-*
-*RETURNS:
-* It fills the locations pointed by feedback_divider_param
-* and fract_feedback_divider_param
-* It returns - true if feedback divider not 0
-* - false should never happen)
-*/
+ * Function: calculate_fb_and_fractional_fb_divider
+ *
+ * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
+ *
+ *PARAMETERS:
+ * targetPixelClock Desired frequency in 100 Hz
+ * ref_divider Reference divider (already known)
+ * postDivider Post Divider (already known)
+ * feedback_divider_param Pointer where to store
+ * calculated feedback divider value
+ * fract_feedback_divider_param Pointer where to store
+ * calculated fract feedback divider value
+ *
+ *RETURNS:
+ * It fills the locations pointed by feedback_divider_param
+ * and fract_feedback_divider_param
+ * It returns - true if feedback divider not 0
+ * - false should never happen)
+ */
static bool calculate_fb_and_fractional_fb_divider(
struct calc_pll_clock_source *calc_pll_cs,
- uint32_t target_pix_clk_khz,
+ uint32_t target_pix_clk_100hz,
uint32_t ref_divider,
uint32_t post_divider,
uint32_t *feedback_divider_param,
@@ -138,11 +138,11 @@ static bool calculate_fb_and_fractional_fb_divider(
uint64_t feedback_divider;
feedback_divider =
- (uint64_t)target_pix_clk_khz * ref_divider * post_divider;
+ (uint64_t)target_pix_clk_100hz * ref_divider * post_divider;
feedback_divider *= 10;
/* additional factor, since we divide by 10 afterwards */
feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
- feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz);
+ feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull);
/*Round to the number of precision
* The following code replace the old code (ullfeedbackDivider + 5)/10
@@ -195,36 +195,36 @@ static bool calc_fb_divider_checking_tolerance(
{
uint32_t feedback_divider;
uint32_t fract_feedback_divider;
- uint32_t actual_calculated_clock_khz;
+ uint32_t actual_calculated_clock_100hz;
uint32_t abs_err;
- uint64_t actual_calc_clk_khz;
+ uint64_t actual_calc_clk_100hz;
calculate_fb_and_fractional_fb_divider(
calc_pll_cs,
- pll_settings->adjusted_pix_clk,
+ pll_settings->adjusted_pix_clk_100hz,
ref_divider,
post_divider,
&feedback_divider,
&fract_feedback_divider);
/*Actual calculated value*/
- actual_calc_clk_khz = (uint64_t)feedback_divider *
+ actual_calc_clk_100hz = (uint64_t)feedback_divider *
calc_pll_cs->fract_fb_divider_factor +
fract_feedback_divider;
- actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz;
- actual_calc_clk_khz =
- div_u64(actual_calc_clk_khz,
+ actual_calc_clk_100hz *= calc_pll_cs->ref_freq_khz * 10;
+ actual_calc_clk_100hz =
+ div_u64(actual_calc_clk_100hz,
ref_divider * post_divider *
calc_pll_cs->fract_fb_divider_factor);
- actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz);
+ actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz);
- abs_err = (actual_calculated_clock_khz >
- pll_settings->adjusted_pix_clk)
- ? actual_calculated_clock_khz -
- pll_settings->adjusted_pix_clk
- : pll_settings->adjusted_pix_clk -
- actual_calculated_clock_khz;
+ abs_err = (actual_calculated_clock_100hz >
+ pll_settings->adjusted_pix_clk_100hz)
+ ? actual_calculated_clock_100hz -
+ pll_settings->adjusted_pix_clk_100hz
+ : pll_settings->adjusted_pix_clk_100hz -
+ actual_calculated_clock_100hz;
if (abs_err <= tolerance) {
/*found good values*/
@@ -233,10 +233,10 @@ static bool calc_fb_divider_checking_tolerance(
pll_settings->feedback_divider = feedback_divider;
pll_settings->fract_feedback_divider = fract_feedback_divider;
pll_settings->pix_clk_post_divider = post_divider;
- pll_settings->calculated_pix_clk =
- actual_calculated_clock_khz;
+ pll_settings->calculated_pix_clk_100hz =
+ actual_calculated_clock_100hz;
pll_settings->vco_freq =
- actual_calculated_clock_khz * post_divider;
+ actual_calculated_clock_100hz * post_divider / 10;
return true;
}
return false;
@@ -257,8 +257,8 @@ static bool calc_pll_dividers_in_range(
/* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
* This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
- tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) /
- 10000;
+ tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) /
+ 100000;
if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
@@ -294,7 +294,7 @@ static uint32_t calculate_pixel_clock_pll_dividers(
uint32_t min_ref_divider;
uint32_t max_ref_divider;
- if (pll_settings->adjusted_pix_clk == 0) {
+ if (pll_settings->adjusted_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s Bad requested pixel clock", __func__);
return MAX_PLL_CALC_ERROR;
@@ -306,21 +306,21 @@ static uint32_t calculate_pixel_clock_pll_dividers(
max_post_divider = pll_settings->pix_clk_post_divider;
} else {
min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
- if (min_post_divider * pll_settings->adjusted_pix_clk <
- calc_pll_cs->min_vco_khz) {
- min_post_divider = calc_pll_cs->min_vco_khz /
- pll_settings->adjusted_pix_clk;
+ if (min_post_divider * pll_settings->adjusted_pix_clk_100hz <
+ calc_pll_cs->min_vco_khz * 10) {
+ min_post_divider = calc_pll_cs->min_vco_khz * 10 /
+ pll_settings->adjusted_pix_clk_100hz;
if ((min_post_divider *
- pll_settings->adjusted_pix_clk) <
- calc_pll_cs->min_vco_khz)
+ pll_settings->adjusted_pix_clk_100hz) <
+ calc_pll_cs->min_vco_khz * 10)
min_post_divider++;
}
max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
- if (max_post_divider * pll_settings->adjusted_pix_clk
- > calc_pll_cs->max_vco_khz)
- max_post_divider = calc_pll_cs->max_vco_khz /
- pll_settings->adjusted_pix_clk;
+ if (max_post_divider * pll_settings->adjusted_pix_clk_100hz
+ > calc_pll_cs->max_vco_khz * 10)
+ max_post_divider = calc_pll_cs->max_vco_khz * 10 /
+ pll_settings->adjusted_pix_clk_100hz;
}
/* 2) Find Reference divider ranges
@@ -392,47 +392,47 @@ static bool pll_adjust_pix_clk(
struct pixel_clk_params *pix_clk_params,
struct pll_settings *pll_settings)
{
- uint32_t actual_pix_clk_khz = 0;
- uint32_t requested_clk_khz = 0;
+ uint32_t actual_pix_clk_100hz = 0;
+ uint32_t requested_clk_100hz = 0;
struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
0 };
enum bp_result bp_result;
switch (pix_clk_params->signal_type) {
case SIGNAL_TYPE_HDMI_TYPE_A: {
- requested_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
switch (pix_clk_params->color_depth) {
case COLOR_DEPTH_101010:
- requested_clk_khz = (requested_clk_khz * 5) >> 2;
+ requested_clk_100hz = (requested_clk_100hz * 5) >> 2;
break; /* x1.25*/
case COLOR_DEPTH_121212:
- requested_clk_khz = (requested_clk_khz * 6) >> 2;
+ requested_clk_100hz = (requested_clk_100hz * 6) >> 2;
break; /* x1.5*/
case COLOR_DEPTH_161616:
- requested_clk_khz = requested_clk_khz * 2;
+ requested_clk_100hz = requested_clk_100hz * 2;
break; /* x2.0*/
default:
break;
}
}
- actual_pix_clk_khz = requested_clk_khz;
+ actual_pix_clk_100hz = requested_clk_100hz;
}
break;
case SIGNAL_TYPE_DISPLAY_PORT:
case SIGNAL_TYPE_DISPLAY_PORT_MST:
case SIGNAL_TYPE_EDP:
- requested_clk_khz = pix_clk_params->requested_sym_clk;
- actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_sym_clk * 10;
+ actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
break;
default:
- requested_clk_khz = pix_clk_params->requested_pix_clk;
- actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
+ actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
break;
}
- bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz;
+ bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10;
bp_adjust_pixel_clock_params.
encoder_object_id = pix_clk_params->encoder_object_id;
bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
@@ -441,9 +441,9 @@ static bool pll_adjust_pix_clk(
bp_result = clk_src->bios->funcs->adjust_pixel_clock(
clk_src->bios, &bp_adjust_pixel_clock_params);
if (bp_result == BP_RESULT_OK) {
- pll_settings->actual_pix_clk = actual_pix_clk_khz;
- pll_settings->adjusted_pix_clk =
- bp_adjust_pixel_clock_params.adjusted_pixel_clock;
+ pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz;
+ pll_settings->adjusted_pix_clk_100hz =
+ bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10;
pll_settings->reference_divider =
bp_adjust_pixel_clock_params.reference_divider;
pll_settings->pix_clk_post_divider =
@@ -490,7 +490,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
const struct spread_spectrum_data *ss_data = get_ss_data_entry(
clk_src,
pix_clk_params->signal_type,
- pll_settings->adjusted_pix_clk);
+ pll_settings->adjusted_pix_clk_100hz / 10);
if (NULL != ss_data)
pll_settings->ss_percentage = ss_data->percentage;
@@ -502,13 +502,13 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
* to continue. */
DC_LOG_ERROR(
"%s: Failed to adjust pixel clock!!", __func__);
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
- pll_settings->adjusted_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
+ pll_settings->adjusted_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
if (dc_is_dp_signal(pix_clk_params->signal_type))
- pll_settings->adjusted_pix_clk = 100000;
+ pll_settings->adjusted_pix_clk_100hz = 1000000;
}
/* Calculate Dividers */
@@ -533,28 +533,28 @@ static void dce112_get_pix_clk_dividers_helper (
struct pll_settings *pll_settings,
struct pixel_clk_params *pix_clk_params)
{
- uint32_t actualPixelClockInKHz;
+ uint32_t actual_pixel_clock_100hz;
- actualPixelClockInKHz = pix_clk_params->requested_pix_clk;
+ actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
/* Calculate Dividers */
if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
switch (pix_clk_params->color_depth) {
case COLOR_DEPTH_101010:
- actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2;
+ actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
break;
case COLOR_DEPTH_121212:
- actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2;
+ actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
break;
case COLOR_DEPTH_161616:
- actualPixelClockInKHz = actualPixelClockInKHz * 2;
+ actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
break;
default:
break;
}
}
- pll_settings->actual_pix_clk = actualPixelClockInKHz;
- pll_settings->adjusted_pix_clk = actualPixelClockInKHz;
- pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk;
+ pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz;
+ pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz;
+ pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
}
static uint32_t dce110_get_pix_clk_dividers(
@@ -567,7 +567,7 @@ static uint32_t dce110_get_pix_clk_dividers(
DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
- || pix_clk_params->requested_pix_clk == 0) {
+ || pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return pll_calc_error;
@@ -577,10 +577,10 @@ static uint32_t dce110_get_pix_clk_dividers(
if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
- pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
- pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
return 0;
}
@@ -599,7 +599,7 @@ static uint32_t dce112_get_pix_clk_dividers(
DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
- || pix_clk_params->requested_pix_clk == 0) {
+ || pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return -1;
@@ -609,10 +609,10 @@ static uint32_t dce112_get_pix_clk_dividers(
if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
- pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
- pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
return -1;
}
@@ -714,7 +714,7 @@ static bool enable_spread_spectrum(
ss_data = get_ss_data_entry(
clk_src,
signal,
- pll_settings->calculated_pix_clk);
+ pll_settings->calculated_pix_clk_100hz / 10);
/* Pixel clock PLL has been programmed to generate desired pixel clock,
* now enable SS on pixel clock */
@@ -853,7 +853,7 @@ static bool dce110_program_pix_clk(
/*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 = pll_settings->actual_pix_clk;
+ 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;
@@ -903,12 +903,12 @@ static bool dce112_program_pix_clk(
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
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_kHz = 700000;
- unsigned clock_kHz = pll_settings->actual_pix_clk;
+ 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_kHz);
- REG_WRITE(MODULO[inst], dp_dto_ref_kHz);
+ 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);
@@ -927,7 +927,7 @@ static bool dce112_program_pix_clk(
/*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 = pll_settings->actual_pix_clk;
+ 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;
@@ -977,6 +977,28 @@ static bool dce110_clock_source_power_down(
return bp_result == BP_RESULT_OK;
}
+static bool get_pixel_clk_frequency_100hz(
+ struct clock_source *clock_source,
+ unsigned int inst,
+ unsigned int *pixel_clk_khz)
+{
+ struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
+ unsigned int clock_hz = 0;
+
+ if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
+ clock_hz = REG_READ(PHASE[inst]);
+
+ /* NOTE: There is agreement with VBIOS here that MODULO is
+ * programmed equal to DPREFCLK, in which case PHASE will be
+ * equivalent to pixel clock.
+ */
+ *pixel_clk_khz = clock_hz / 100;
+ return true;
+ }
+
+ return false;
+}
+
/*****************************************/
/* Constructor */
/*****************************************/
@@ -984,12 +1006,14 @@ static bool dce110_clock_source_power_down(
static const struct clock_source_funcs dce112_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dce112_program_pix_clk,
- .get_pix_clk_dividers = dce112_get_pix_clk_dividers
+ .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
+ .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
};
static const struct clock_source_funcs dce110_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dce110_program_pix_clk,
- .get_pix_clk_dividers = dce110_get_pix_clk_dividers
+ .get_pix_clk_dividers = dce110_get_pix_clk_dividers,
+ .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
};
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 dea40b322191..c2926cf19dee 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -51,7 +51,6 @@
#define PSR_SET_WAITLOOP 0x31
#define MCP_INIT_DMCU 0x88
#define MCP_INIT_IRAM 0x89
-#define MCP_DMCU_VERSION 0x90
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
static bool dce_dmcu_init(struct dmcu *dmcu)
@@ -317,38 +316,11 @@ static void dce_get_psr_wait_loop(
}
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-static void dcn10_get_dmcu_state(struct dmcu *dmcu)
-{
- struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
- uint32_t dmcu_state_offset = 0xf6;
-
- /* Enable write access to IRAM */
- REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
- IRAM_HOST_ACCESS_EN, 1,
- IRAM_RD_ADDR_AUTO_INC, 1);
-
- REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
-
- /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
- REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_state_offset);
-
- /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
- dmcu->dmcu_state = REG_READ(DMCU_IRAM_RD_DATA);
-
- /* Disable write access to IRAM to allow dynamic sleep state */
- REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
- IRAM_HOST_ACCESS_EN, 0,
- IRAM_RD_ADDR_AUTO_INC, 0);
-}
-
static void dcn10_get_dmcu_version(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t dmcu_version_offset = 0xf1;
- /* Clear scratch */
- REG_WRITE(DC_DMCU_SCRATCH, 0);
-
/* Enable write access to IRAM */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 1,
@@ -359,85 +331,74 @@ static void dcn10_get_dmcu_version(struct dmcu *dmcu)
/* Write address to IRAM_RD_ADDR and read from DATA register */
REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset);
dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA);
- dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
+ dmcu->dmcu_version.abm_version = REG_READ(DMCU_IRAM_RD_DATA);
+ dmcu->dmcu_version.psr_version = REG_READ(DMCU_IRAM_RD_DATA);
+ dmcu->dmcu_version.build_version = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
REG_READ(DMCU_IRAM_RD_DATA));
- dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA);
- dmcu->dmcu_version.date = REG_READ(DMCU_IRAM_RD_DATA);
/* Disable write access to IRAM to allow dynamic sleep state */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 0,
IRAM_RD_ADDR_AUTO_INC, 0);
-
- /* Send MCP command message to DMCU to get version reply from FW.
- * We expect this version should match the one in IRAM, otherwise
- * something is wrong with DMCU and we should fail and disable UC.
- */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
-
- /* Set command to get DMCU version from microcontroller */
- REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
- MCP_DMCU_VERSION);
-
- /* Notify microcontroller of new command */
- REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
-
- /* Ensure command has been executed before continuing */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
-
- /* Somehow version does not match, so fail and return version 0 */
- if (dmcu->dmcu_version.interface_version != REG_READ(DC_DMCU_SCRATCH))
- dmcu->dmcu_version.interface_version = 0;
}
static bool dcn10_dmcu_init(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
+ bool status = false;
- /* DMCU FW should populate the scratch register if running */
- if (REG_READ(DC_DMCU_SCRATCH) == 0)
- return false;
-
- /* Check state is uninitialized */
- dcn10_get_dmcu_state(dmcu);
-
- /* If microcontroller is already initialized, do nothing */
- if (dmcu->dmcu_state == DMCU_RUNNING)
- return true;
-
- /* Retrieve and cache the DMCU firmware version. */
- dcn10_get_dmcu_version(dmcu);
-
- /* Check interface version to confirm firmware is loaded and running */
- if (dmcu->dmcu_version.interface_version == 0)
- return false;
+ /* Definition of DC_DMCU_SCRATCH
+ * 0 : firmare not loaded
+ * 1 : PSP load DMCU FW but not initialized
+ * 2 : Firmware already initialized
+ */
+ dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
- /* Wait until microcontroller is ready to process interrupt */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
+ switch (dmcu->dmcu_state) {
+ case DMCU_UNLOADED:
+ status = false;
+ break;
+ case DMCU_LOADED_UNINITIALIZED:
+ /* Wait until microcontroller is ready to process interrupt */
+ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
- /* Set initialized ramping boundary value */
- REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
+ /* Set initialized ramping boundary value */
+ REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
- /* Set command to initialize microcontroller */
- REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
+ /* Set command to initialize microcontroller */
+ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
MCP_INIT_DMCU);
- /* Notify microcontroller of new command */
- REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
+ /* Notify microcontroller of new command */
+ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
- /* Ensure command has been executed before continuing */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
+ /* Ensure command has been executed before continuing */
+ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
- // Check state is initialized
- dcn10_get_dmcu_state(dmcu);
+ // Check state is initialized
+ dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
- // If microcontroller is not in running state, fail
- if (dmcu->dmcu_state != DMCU_RUNNING)
- return false;
+ // If microcontroller is not in running state, fail
+ if (dmcu->dmcu_state == DMCU_RUNNING) {
+ /* Retrieve and cache the DMCU firmware version. */
+ dcn10_get_dmcu_version(dmcu);
+ status = true;
+ } else
+ status = false;
- return true;
+ break;
+ case DMCU_RUNNING:
+ status = true;
+ break;
+ default:
+ status = false;
+ break;
+ }
+
+ return status;
}
+
static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
unsigned int start_offset,
const char *src,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
index c83a7f05f14c..956bdf14503f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
@@ -133,6 +133,10 @@
SR(DCHUB_AGP_TOP), \
BL_REG_LIST()
+#define HWSEQ_VG20_REG_LIST() \
+ HWSEQ_DCE120_REG_LIST(),\
+ MMHUB_SR(MC_VM_XGMI_LFB_CNTL)
+
#define HWSEQ_DCE112_REG_LIST() \
HWSEQ_DCE10_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \
@@ -298,6 +302,7 @@ struct dce_hwseq_registers {
uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB;
uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR;
uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR;
+ uint32_t MC_VM_XGMI_LFB_CNTL;
uint32_t AZALIA_AUDIO_DTO;
uint32_t AZALIA_CONTROLLER_CLOCK_GATING;
};
@@ -382,6 +387,11 @@ struct dce_hwseq_registers {
HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\
+ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\
+ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh)
+
#define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\
HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \
@@ -470,6 +480,8 @@ struct dce_hwseq_registers {
type PHYSICAL_PAGE_NUMBER_MSB;\
type PHYSICAL_PAGE_NUMBER_LSB;\
type LOGICAL_ADDR; \
+ type PF_LFB_REGION;\
+ type PF_MAX_REGION;\
type ENABLE_L1_TLB;\
type SYSTEM_ACCESS_MODE;\
type LVTMA_BLON;\
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 3e18ea84b1f9..314c04a915d2 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
@@ -599,12 +599,12 @@ bool dce110_link_encoder_validate_dvi_output(
if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) &&
signal != SIGNAL_TYPE_HDMI_TYPE_A &&
- crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK)
+ crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+ if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz > max_pixel_clock)
+ if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10))
return false;
/* DVI supports 6/8bpp single-link and 10/16bpp dual-link */
@@ -788,7 +788,7 @@ bool dce110_link_encoder_validate_output_with_stream(
case SIGNAL_TYPE_DVI_DUAL_LINK:
is_valid = dce110_link_encoder_validate_dvi_output(
enc110,
- stream->sink->link->connector_signal,
+ stream->link->connector_signal,
stream->signal,
&stream->timing);
break;
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 cce0d18f91da..1fa2d4fd7a35 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
@@ -288,9 +288,18 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
#endif
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
-
+ struct dc_crtc_timing hw_crtc_timing = *crtc_timing;
+ if (hw_crtc_timing.flags.INTERLACE) {
+ /*the input timing is in VESA spec format with Interlace flag =1*/
+ hw_crtc_timing.v_total /= 2;
+ hw_crtc_timing.v_border_top /= 2;
+ hw_crtc_timing.v_addressable /= 2;
+ hw_crtc_timing.v_border_bottom /= 2;
+ hw_crtc_timing.v_front_porch /= 2;
+ hw_crtc_timing.v_sync_width /= 2;
+ }
/* set pixel encoding */
- switch (crtc_timing->pixel_encoding) {
+ switch (hw_crtc_timing.pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR422);
@@ -299,8 +308,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR444);
- if (crtc_timing->flags.Y_ONLY)
- if (crtc_timing->display_color_depth != COLOR_DEPTH_666)
+ if (hw_crtc_timing.flags.Y_ONLY)
+ if (hw_crtc_timing.display_color_depth != COLOR_DEPTH_666)
/* HW testing only, no use case yet.
* Color depth of Y-only could be
* 8, 10, 12, 16 bits */
@@ -335,7 +344,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
/* set color depth */
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH,
0);
@@ -363,7 +372,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
colorimetry_bpc = 0;
break;
@@ -401,9 +410,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 0; /*bt601*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_YCBCR709:
@@ -411,9 +420,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 1; /*bt709*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
@@ -453,27 +462,27 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
*/
if (REG(DP_MSA_TIMING_PARAM1))
REG_SET_2(DP_MSA_TIMING_PARAM1, 0,
- DP_MSA_HTOTAL, crtc_timing->h_total,
- DP_MSA_VTOTAL, crtc_timing->v_total);
+ 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
*/
- h_blank = crtc_timing->h_total - crtc_timing->h_border_left -
- crtc_timing->h_addressable - crtc_timing->h_border_right;
+ h_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left -
+ hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right;
- h_back_porch = h_blank - crtc_timing->h_front_porch -
- crtc_timing->h_sync_width;
+ h_back_porch = h_blank - hw_crtc_timing.h_front_porch -
+ hw_crtc_timing.h_sync_width;
/* start at begining of left border */
- h_active_start = crtc_timing->h_sync_width + h_back_porch;
+ h_active_start = hw_crtc_timing.h_sync_width + h_back_porch;
- v_active_start = crtc_timing->v_total - crtc_timing->v_border_top -
- crtc_timing->v_addressable - crtc_timing->v_border_bottom -
- crtc_timing->v_front_porch;
+ v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top -
+ hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom -
+ hw_crtc_timing.v_front_porch;
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@@ -486,21 +495,21 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
if (REG(DP_MSA_TIMING_PARAM3))
REG_SET_4(DP_MSA_TIMING_PARAM3, 0,
DP_MSA_HSYNCWIDTH,
- crtc_timing->h_sync_width,
+ hw_crtc_timing.h_sync_width,
DP_MSA_HSYNCPOLARITY,
- !crtc_timing->flags.HSYNC_POSITIVE_POLARITY,
+ !hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY,
DP_MSA_VSYNCWIDTH,
- crtc_timing->v_sync_width,
+ hw_crtc_timing.v_sync_width,
DP_MSA_VSYNCPOLARITY,
- !crtc_timing->flags.VSYNC_POSITIVE_POLARITY);
+ !hw_crtc_timing.flags.VSYNC_POSITIVE_POLARITY);
/* HWDITH include border or overscan */
if (REG(DP_MSA_TIMING_PARAM4))
REG_SET_2(DP_MSA_TIMING_PARAM4, 0,
- DP_MSA_HWIDTH, crtc_timing->h_border_left +
- crtc_timing->h_addressable + crtc_timing->h_border_right,
- DP_MSA_VHEIGHT, crtc_timing->v_border_top +
- crtc_timing->v_addressable + crtc_timing->v_border_bottom);
+ DP_MSA_HWIDTH, hw_crtc_timing.h_border_left +
+ 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
@@ -662,7 +671,7 @@ static void dce110_stream_encoder_dvi_set_stream_attribute(
cntl.signal = is_dual_link ?
SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK;
cntl.enable_dp_audio = false;
- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+ cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
if (enc110->base.bp->funcs->encoder_control(
@@ -686,7 +695,7 @@ static void dce110_stream_encoder_lvds_set_stream_attribute(
cntl.engine_id = enc110->base.id;
cntl.signal = SIGNAL_TYPE_LVDS;
cntl.enable_dp_audio = false;
- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+ cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
cntl.lanes_number = LANE_COUNT_FOUR;
if (enc110->base.bp->funcs->encoder_control(
@@ -1575,6 +1584,14 @@ static void setup_stereo_sync(
REG_UPDATE(DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, !enable);
}
+static void dig_connect_to_otg(
+ struct stream_encoder *enc,
+ int tg_inst)
+{
+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+
+ REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
+}
static const struct stream_encoder_funcs dce110_str_enc_funcs = {
.dp_set_stream_attribute =
@@ -1609,7 +1626,7 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = {
.hdmi_audio_disable = dce110_se_hdmi_audio_disable,
.setup_stereo_sync = setup_stereo_sync,
.set_avmute = dce110_stream_encoder_set_avmute,
-
+ .dig_connect_to_otg = dig_connect_to_otg,
};
void dce110_stream_encoder_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
index 6c28229c76eb..f9cdf2b5242c 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
@@ -199,7 +199,8 @@
SE_SF(DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
SE_SF(DP_SEC_CNTL, DP_SEC_AIP_ENABLE, mask_sh),\
SE_SF(DP_SEC_CNTL, DP_SEC_ACM_ENABLE, mask_sh),\
- SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh)
+ SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh),\
+ SE_SF(DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh)
#define SE_COMMON_MASK_SH_LIST_DCE_COMMON(mask_sh)\
SE_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh)
@@ -284,7 +285,8 @@
SE_SF(DIG0_DIG_FE_CNTL, TMDS_PIXEL_ENCODING, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, TMDS_COLOR_FORMAT, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\
- SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh)
+ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
+ SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh)
#define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\
SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh)
@@ -494,6 +496,7 @@ struct dce_stream_encoder_shift {
uint8_t HDMI_DB_DISABLE;
uint8_t DP_VID_N_MUL;
uint8_t DP_VID_M_DOUBLE_VALUE_EN;
+ uint8_t DIG_SOURCE_SELECT;
};
struct dce_stream_encoder_mask {
@@ -624,6 +627,7 @@ struct dce_stream_encoder_mask {
uint32_t HDMI_DB_DISABLE;
uint32_t DP_VID_N_MUL;
uint32_t DP_VID_M_DOUBLE_VALUE_EN;
+ uint32_t DIG_SOURCE_SELECT;
};
struct dce110_stream_enc_registers {
diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
index 6ae51a5dfc04..23044e6723e8 100644
--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
@@ -76,6 +76,7 @@
#ifndef mmBIOS_SCRATCH_2
#define mmBIOS_SCRATCH_2 0x05CB
+ #define mmBIOS_SCRATCH_3 0x05CC
#define mmBIOS_SCRATCH_6 0x05CF
#endif
@@ -365,6 +366,7 @@ static const struct dce_abm_mask abm_mask = {
#define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03
static const struct bios_registers bios_regs = {
+ .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3,
.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6
};
@@ -587,7 +589,7 @@ struct output_pixel_processor *dce100_opp_create(
return &opp->base;
}
-struct aux_engine *dce100_aux_engine_create(
+struct dce_aux *dce100_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
index 52d50e24a995..7b23239d33fe 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
@@ -62,8 +62,6 @@ static const struct dce110_compressor_reg_offsets reg_offsets[] = {
}
};
-static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600;
-
static uint32_t align_to_chunks_number_per_line(uint32_t pixels)
{
return 256 * ((pixels + 255) / 256);
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 4bf24758217f..e1b285ea01ac 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
@@ -614,55 +614,6 @@ dce110_set_output_transfer_func(struct pipe_ctx *pipe_ctx,
return true;
}
-static enum dc_status bios_parser_crtc_source_select(
- struct pipe_ctx *pipe_ctx)
-{
- struct dc_bios *dcb;
- /* call VBIOS table to set CRTC source for the HW
- * encoder block
- * note: video bios clears all FMT setting here. */
- struct bp_crtc_source_select crtc_source_select = {0};
- const struct dc_sink *sink = pipe_ctx->stream->sink;
-
- crtc_source_select.engine_id = pipe_ctx->stream_res.stream_enc->id;
- crtc_source_select.controller_id = pipe_ctx->stream_res.tg->inst + 1;
- /*TODO: Need to un-hardcode color depth, dp_audio and account for
- * the case where signal and sink signal is different (translator
- * encoder)*/
- crtc_source_select.signal = pipe_ctx->stream->signal;
- crtc_source_select.enable_dp_audio = false;
- crtc_source_select.sink_signal = pipe_ctx->stream->signal;
-
- switch (pipe_ctx->stream->timing.display_color_depth) {
- case COLOR_DEPTH_666:
- crtc_source_select.display_output_bit_depth = PANEL_6BIT_COLOR;
- break;
- case COLOR_DEPTH_888:
- crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR;
- break;
- case COLOR_DEPTH_101010:
- crtc_source_select.display_output_bit_depth = PANEL_10BIT_COLOR;
- break;
- case COLOR_DEPTH_121212:
- crtc_source_select.display_output_bit_depth = PANEL_12BIT_COLOR;
- break;
- default:
- BREAK_TO_DEBUGGER();
- crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR;
- break;
- }
-
- dcb = sink->ctx->dc_bios;
-
- if (BP_RESULT_OK != dcb->funcs->crtc_source_select(
- dcb,
- &crtc_source_select)) {
- return DC_ERROR_UNEXPECTED;
- }
-
- return DC_OK;
-}
-
void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
{
bool is_hdmi;
@@ -692,10 +643,10 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
{
enum dc_lane_count lane_count =
- pipe_ctx->stream->sink->link->cur_link_settings.lane_count;
+ pipe_ctx->stream->link->cur_link_settings.lane_count;
struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
- struct dc_link *link = pipe_ctx->stream->sink->link;
+ struct dc_link *link = pipe_ctx->stream->link;
uint32_t active_total_with_borders;
@@ -1000,7 +951,7 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
- if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL)
+ if (num_audio >= 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL)
/*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
pp_smu->set_pme_wa_enable(&pp_smu->pp_smu);
/* un-mute audio */
@@ -1017,6 +968,8 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option)
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, true);
if (pipe_ctx->stream_res.audio) {
+ struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
+
if (option != KEEP_ACQUIRED_RESOURCE ||
!dc->debug.az_endpoint_mute_only) {
/*only disalbe az_endpoint if power down or free*/
@@ -1036,6 +989,9 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option)
update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false);
pipe_ctx->stream_res.audio = NULL;
}
+ if (pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL)
+ /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
+ pp_smu->set_pme_wa_enable(&pp_smu->pp_smu);
/* TODO: notify audio driver for if audio modes list changed
* add audio mode list change flag */
@@ -1048,7 +1004,7 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option)
void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
struct dc *dc = pipe_ctx->stream->ctx->dc;
if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
@@ -1073,11 +1029,10 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
{
struct encoder_unblank_param params = { { 0 } };
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
/* only 3 items below are used by unblank */
- params.pixel_clk_khz =
- pipe_ctx->stream->timing.pix_clk_khz;
+ params.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
params.link_settings.link_rate = link_settings->link_rate;
if (dc_is_dp_signal(pipe_ctx->stream->signal))
@@ -1087,10 +1042,11 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
link->dc->hwss.edp_backlight_control(link, true);
}
}
+
void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
+ struct dc_link *link = stream->link;
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
link->dc->hwss.edp_backlight_control(link, false);
@@ -1163,27 +1119,27 @@ static void build_audio_output(
stream->timing.flags.INTERLACE;
audio_output->crtc_info.refresh_rate =
- (stream->timing.pix_clk_khz*1000)/
+ (stream->timing.pix_clk_100hz*10000)/
(stream->timing.h_total*stream->timing.v_total);
audio_output->crtc_info.color_depth =
stream->timing.display_color_depth;
audio_output->crtc_info.requested_pixel_clock =
- pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
audio_output->crtc_info.calculated_pixel_clock =
- pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
/*for HDMI, audio ACR is with deep color ratio factor*/
if (dc_is_hdmi_signal(pipe_ctx->stream->signal) &&
audio_output->crtc_info.requested_pixel_clock ==
- stream->timing.pix_clk_khz) {
+ (stream->timing.pix_clk_100hz / 10)) {
if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
audio_output->crtc_info.requested_pixel_clock =
audio_output->crtc_info.requested_pixel_clock/2;
audio_output->crtc_info.calculated_pixel_clock =
- pipe_ctx->stream_res.pix_clk_params.requested_pix_clk/2;
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/20;
}
}
@@ -1294,8 +1250,6 @@ static enum dc_status dce110_enable_stream_timing(
struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx.
pipe_ctx[pipe_ctx->pipe_idx];
struct tg_color black_color = {0};
- struct drr_params params = {0};
- unsigned int event_triggers = 0;
if (!pipe_ctx_old->stream) {
@@ -1324,20 +1278,6 @@ static enum dc_status dce110_enable_stream_timing(
pipe_ctx->stream_res.tg,
&stream->timing,
true);
-
- params.vertical_total_min = stream->adjust.v_total_min;
- params.vertical_total_max = stream->adjust.v_total_max;
- if (pipe_ctx->stream_res.tg->funcs->set_drr)
- pipe_ctx->stream_res.tg->funcs->set_drr(
- pipe_ctx->stream_res.tg, &params);
-
- // DRR should set trigger event to monitor surface update event
- if (stream->adjust.v_total_min != 0 &&
- stream->adjust.v_total_max != 0)
- event_triggers = 0x80;
- if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
- pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
- pipe_ctx->stream_res.tg, event_triggers);
}
if (!pipe_ctx_old->stream) {
@@ -1357,6 +1297,8 @@ static enum dc_status apply_single_controller_ctx_to_hw(
struct dc *dc)
{
struct dc_stream_state *stream = pipe_ctx->stream;
+ struct drr_params params = {0};
+ unsigned int event_triggers = 0;
if (pipe_ctx->stream_res.audio != NULL) {
struct audio_output audio_output;
@@ -1383,14 +1325,32 @@ static enum dc_status apply_single_controller_ctx_to_hw(
}
/* */
- dc->hwss.enable_stream_timing(pipe_ctx, context, dc);
+ /* Do not touch stream timing on seamless boot optimization. */
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ dc->hwss.enable_stream_timing(pipe_ctx, context, dc);
+
+ if (pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt)
+ pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt(
+ pipe_ctx->stream_res.tg,
+ &stream->timing);
+
+ params.vertical_total_min = stream->adjust.v_total_min;
+ params.vertical_total_max = stream->adjust.v_total_max;
+ if (pipe_ctx->stream_res.tg->funcs->set_drr)
+ pipe_ctx->stream_res.tg->funcs->set_drr(
+ pipe_ctx->stream_res.tg, &params);
+
+ // DRR should set trigger event to monitor surface update event
+ if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
+ event_triggers = 0x80;
+ if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
+ pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
+ pipe_ctx->stream_res.tg, event_triggers);
- /* TODO: move to stream encoder */
if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL)
- if (DC_OK != bios_parser_crtc_source_select(pipe_ctx)) {
- BREAK_TO_DEBUGGER();
- return DC_ERROR_UNEXPECTED;
- }
+ pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.tg->inst);
pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
pipe_ctx->stream_res.opp,
@@ -1408,7 +1368,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
- pipe_ctx->stream->sink->link->psr_enabled = false;
+ pipe_ctx->stream->link->psr_enabled = false;
return DC_OK;
}
@@ -1518,7 +1478,7 @@ static struct dc_link *get_link_for_edp(struct dc *dc)
return NULL;
}
-static struct dc_link *get_link_for_edp_not_in_use(
+static struct dc_link *get_link_for_edp_to_turn_off(
struct dc *dc,
struct dc_state *context)
{
@@ -1527,8 +1487,12 @@ static struct dc_link *get_link_for_edp_not_in_use(
/* check if eDP panel is suppose to be set mode, if yes, no need to disable */
for (i = 0; i < context->stream_count; i++) {
- if (context->streams[i]->signal == SIGNAL_TYPE_EDP)
- return NULL;
+ if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
+ if (context->streams[i]->dpms_off == true)
+ return context->streams[i]->sink->link;
+ else
+ return NULL;
+ }
}
/* check if there is an eDP panel not in use */
@@ -1555,7 +1519,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
int i;
struct dc_link *edp_link_to_turnoff = NULL;
struct dc_link *edp_link = get_link_for_edp(dc);
- struct dc_bios *bios = dc->ctx->dc_bios;
bool can_edp_fast_boot_optimize = false;
bool apply_edp_fast_boot_optimization = false;
@@ -1571,7 +1534,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
}
if (can_edp_fast_boot_optimize)
- edp_link_to_turnoff = get_link_for_edp_not_in_use(dc, context);
+ edp_link_to_turnoff = get_link_for_edp_to_turn_off(dc, context);
/* if OS doesn't light up eDP and eDP link is available, we want to disable
* If resume from S4/S5, should optimization.
@@ -1582,20 +1545,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
context->streams[i]->apply_edp_fast_boot_optimization = true;
apply_edp_fast_boot_optimization = true;
-
- /* When after S4 and S5, vbios may post edp and previous dpms_off
- * doesn't make sense.
- * Update dpms_off state to align hw and sw state via check
- * vBios scratch register.
- */
- if (bios->funcs->is_active_display) {
- const struct connector_device_tag_info *device_tag = &(edp_link->device_tag);
-
- if (bios->funcs->is_active_display(bios,
- context->streams[i]->signal,
- device_tag))
- context->streams[i]->dpms_off = false;
- }
}
}
}
@@ -1624,8 +1573,8 @@ static uint32_t compute_pstate_blackout_duration(
pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24;
total_dest_line_time_ns = 1000000UL *
- stream->timing.h_total /
- stream->timing.pix_clk_khz +
+ (stream->timing.h_total * 10) /
+ stream->timing.pix_clk_100hz +
pstate_blackout_duration_ns;
return total_dest_line_time_ns;
@@ -1813,18 +1762,15 @@ static bool should_enable_fbc(struct dc *dc,
if (i == dc->res_pool->pipe_count)
return false;
- if (!pipe_ctx->stream->sink)
- return false;
-
- if (!pipe_ctx->stream->sink->link)
+ if (!pipe_ctx->stream->link)
return false;
/* Only supports eDP */
- if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP)
+ if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP)
return false;
/* PSR should not be enabled */
- if (pipe_ctx->stream->sink->link->psr_enabled)
+ if (pipe_ctx->stream->link->psr_enabled)
return false;
/* Nothing to compress */
@@ -2329,6 +2275,11 @@ static void dce110_enable_per_frame_crtc_position_reset(
}
+static void init_pipes(struct dc *dc, struct dc_state *context)
+{
+ // Do nothing
+}
+
static void init_hw(struct dc *dc)
{
int i;
@@ -2573,7 +2524,7 @@ static void dce110_apply_ctx_for_surface(
pipe_ctx->plane_res.mi,
pipe_ctx->stream->timing.h_total,
pipe_ctx->stream->timing.v_total,
- pipe_ctx->stream->timing.pix_clk_khz,
+ pipe_ctx->stream->timing.pix_clk_100hz / 10,
context->stream_count);
dce110_program_front_end_for_pipe(dc, pipe_ctx);
@@ -2595,7 +2546,7 @@ static void dce110_apply_ctx_for_surface(
}
if (dc->fbc_compressor)
- enable_fbc(dc, dc->current_state);
+ enable_fbc(dc, context);
}
static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx)
@@ -2622,13 +2573,35 @@ static void dce110_wait_for_mpcc_disconnect(
/* do nothing*/
}
+static void program_output_csc(struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ enum dc_color_space colorspace,
+ uint16_t *matrix,
+ int opp_id)
+{
+ int i;
+ struct out_csc_color_matrix tbl_entry;
+
+ if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
+ enum dc_color_space color_space = pipe_ctx->stream->output_color_space;
+
+ for (i = 0; i < 12; i++)
+ tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
+
+ tbl_entry.color_space = color_space;
+
+ pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment(
+ pipe_ctx->plane_res.xfm, &tbl_entry);
+ }
+}
+
void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
{
struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
struct mem_input *mi = pipe_ctx->plane_res.mi;
struct dc_cursor_mi_param param = {
- .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz,
+ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz,
.viewport = pipe_ctx->plane_res.scl_data.viewport,
.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
@@ -2672,7 +2645,9 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
static const struct hw_sequencer_funcs dce110_funcs = {
.program_gamut_remap = program_gamut_remap,
+ .program_output_csc = program_output_csc,
.init_hw = init_hw,
+ .init_pipes = init_pipes,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = dce110_apply_ctx_for_surface,
.update_plane_addr = update_plane_addr,
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
index e33d11785b1f..7549adaa1542 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
@@ -84,6 +84,7 @@
#ifndef mmBIOS_SCRATCH_2
#define mmBIOS_SCRATCH_2 0x05CB
+ #define mmBIOS_SCRATCH_3 0x05CC
#define mmBIOS_SCRATCH_6 0x05CF
#endif
@@ -369,6 +370,7 @@ static const struct dce110_clk_src_mask cs_mask = {
};
static const struct bios_registers bios_regs = {
+ .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3,
.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6
};
@@ -606,7 +608,7 @@ static struct output_pixel_processor *dce110_opp_create(
return &opp->base;
}
-struct aux_engine *dce110_aux_engine_create(
+struct dce_aux *dce110_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
@@ -779,8 +781,8 @@ static void get_pixel_clock_parameters(
* the pixel clock normalization for hdmi up to here instead of doing it
* in pll_adjust_pix_clk
*/
- pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz;
- pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id;
+ pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
+ pixel_clk_params->encoder_object_id = stream->link->link_enc->id;
pixel_clk_params->signal_type = pipe_ctx->stream->signal;
pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1;
/* TODO: un-hardcode*/
@@ -797,10 +799,10 @@ static void get_pixel_clock_parameters(
pixel_clk_params->color_depth = COLOR_DEPTH_888;
}
if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
- pixel_clk_params->requested_pix_clk = pixel_clk_params->requested_pix_clk / 2;
+ pixel_clk_params->requested_pix_clk_100hz = pixel_clk_params->requested_pix_clk_100hz / 2;
}
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
- pixel_clk_params->requested_pix_clk *= 2;
+ pixel_clk_params->requested_pix_clk_100hz *= 2;
}
@@ -874,7 +876,7 @@ static bool dce110_validate_bandwidth(
__func__,
context->streams[0]->timing.h_addressable,
context->streams[0]->timing.v_addressable,
- context->streams[0]->timing.pix_clk_khz);
+ context->streams[0]->timing.pix_clk_100hz / 10);
if (memcmp(&dc->current_state->bw.dce,
&context->bw.dce, sizeof(context->bw.dce))) {
@@ -1055,7 +1057,7 @@ static struct pipe_ctx *dce110_acquire_underlay(
pipe_ctx->plane_res.mi->funcs->allocate_mem_input(pipe_ctx->plane_res.mi,
stream->timing.h_total,
stream->timing.v_total,
- stream->timing.pix_clk_khz,
+ stream->timing.pix_clk_100hz / 10,
context->stream_count);
color_space_to_black_color(dc,
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 969d4e72dc94..ea3065d63372 100644
--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
@@ -76,6 +76,7 @@
#ifndef mmBIOS_SCRATCH_2
#define mmBIOS_SCRATCH_2 0x05CB
+ #define mmBIOS_SCRATCH_3 0x05CC
#define mmBIOS_SCRATCH_6 0x05CF
#endif
@@ -376,6 +377,7 @@ static const struct dce110_clk_src_mask cs_mask = {
};
static const struct bios_registers bios_regs = {
+ .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3,
.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6
};
@@ -607,7 +609,7 @@ struct output_pixel_processor *dce112_opp_create(
return &opp->base;
}
-struct aux_engine *dce112_aux_engine_create(
+struct dce_aux *dce112_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
@@ -763,7 +765,7 @@ static struct clock_source *find_matching_pll(
const struct resource_pool *pool,
const struct dc_stream_state *const stream)
{
- switch (stream->sink->link->link_enc->transmitter) {
+ switch (stream->link->link_enc->transmitter) {
case TRANSMITTER_UNIPHY_A:
return pool->clock_sources[DCE112_CLK_SRC_PLL0];
case TRANSMITTER_UNIPHY_B:
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
index eb0f5f9a973b..1ca30928025e 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
@@ -244,6 +244,21 @@ static void dce120_update_dchub(
dh_data->dchub_info_valid = false;
}
+/**
+ * dce121_xgmi_enabled() - Check if xGMI is enabled
+ * @hws: DCE hardware sequencer object
+ *
+ * Return true if xGMI is enabled. False otherwise.
+ */
+bool dce121_xgmi_enabled(struct dce_hwseq *hws)
+{
+ uint32_t pf_max_region;
+
+ REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region);
+ /* PF_MAX_REGION == 0 means xgmi is disabled */
+ return !!pf_max_region;
+}
+
void dce120_hw_sequencer_construct(struct dc *dc)
{
/* All registers used by dce11.2 match those in dce11 in offset and
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
index 77a6b86d7606..c51afbd0b012 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
@@ -30,6 +30,7 @@
struct dc;
+bool dce121_xgmi_enabled(struct dce_hwseq *hws);
void dce120_hw_sequencer_construct(struct dc *dc);
#endif /* __DC_HWSS_DCE112_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
index f12696674eb0..312a0aebf91f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -62,6 +62,8 @@
#include "soc15_hw_ip.h"
#include "vega10_ip_offset.h"
#include "nbio/nbio_6_1_offset.h"
+#include "mmhub/mmhub_9_4_0_offset.h"
+#include "mmhub/mmhub_9_4_0_sh_mask.h"
#include "reg_helper.h"
#include "dce100/dce100_resource.h"
@@ -139,6 +141,17 @@ static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = {
.reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
+/* MMHUB */
+#define MMHUB_BASE_INNER(seg) \
+ MMHUB_BASE__INST0_SEG ## seg
+
+#define MMHUB_BASE(seg) \
+ MMHUB_BASE_INNER(seg)
+
+#define MMHUB_SR(reg_name)\
+ .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \
+ mm ## reg_name
+
/* macros to expend register list macro defined in HW object header file
* end *********************/
@@ -378,7 +391,7 @@ struct output_pixel_processor *dce120_opp_create(
ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask);
return &opp->base;
}
-struct aux_engine *dce120_aux_engine_create(
+struct dce_aux *dce120_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
@@ -429,6 +442,7 @@ struct dce_i2c_hw *dce120_i2c_hw_create(
return dce_i2c_hw;
}
static const struct bios_registers bios_regs = {
+ .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3 + NBIO_BASE(mmBIOS_SCRATCH_3_BASE_IDX),
.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX)
};
@@ -681,6 +695,19 @@ static const struct dce_hwseq_mask hwseq_mask = {
HWSEQ_DCE12_MASK_SH_LIST(_MASK)
};
+/* HWSEQ regs for VG20 */
+static const struct dce_hwseq_registers dce121_hwseq_reg = {
+ HWSEQ_VG20_REG_LIST()
+};
+
+static const struct dce_hwseq_shift dce121_hwseq_shift = {
+ HWSEQ_VG20_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_hwseq_mask dce121_hwseq_mask = {
+ HWSEQ_VG20_MASK_SH_LIST(_MASK)
+};
+
static struct dce_hwseq *dce120_hwseq_create(
struct dc_context *ctx)
{
@@ -695,6 +722,20 @@ static struct dce_hwseq *dce120_hwseq_create(
return hws;
}
+static struct dce_hwseq *dce121_hwseq_create(
+ struct dc_context *ctx)
+{
+ struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);
+
+ if (hws) {
+ hws->ctx = ctx;
+ hws->regs = &dce121_hwseq_reg;
+ hws->shifts = &dce121_hwseq_shift;
+ hws->masks = &dce121_hwseq_mask;
+ }
+ return hws;
+}
+
static const struct resource_create_funcs res_create_funcs = {
.read_dce_straps = read_dce_straps,
.create_audio = create_audio,
@@ -702,6 +743,14 @@ static const struct resource_create_funcs res_create_funcs = {
.create_hwseq = dce120_hwseq_create,
};
+static const struct resource_create_funcs dce121_res_create_funcs = {
+ .read_dce_straps = read_dce_straps,
+ .create_audio = create_audio,
+ .create_stream_encoder = dce120_stream_encoder_create,
+ .create_hwseq = dce121_hwseq_create,
+};
+
+
#define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) }
static const struct dce_mem_input_registers mi_regs[] = {
mi_inst_regs(0),
@@ -911,7 +960,8 @@ static bool construct(
int j;
struct dc_context *ctx = dc->ctx;
struct irq_service_init_data irq_init_data;
- bool harvest_enabled = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev);
+ static const struct resource_create_funcs *res_funcs;
+ bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev);
uint32_t pipe_fuses;
ctx->dc_bios->regs = &bios_regs;
@@ -975,7 +1025,11 @@ static bool construct(
}
}
- pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+ if (is_vg20)
+ pool->base.clk_mgr = dce121_clk_mgr_create(ctx);
+ else
+ pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+
if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
@@ -1008,14 +1062,14 @@ static bool construct(
if (!pool->base.irqs)
goto irqs_create_fail;
- /* retrieve valid pipe fuses */
- if (harvest_enabled)
+ /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */
+ if (is_vg20)
pipe_fuses = read_pipe_fuses(ctx);
/* index to valid pipe resource */
j = 0;
for (i = 0; i < pool->base.pipe_count; i++) {
- if (harvest_enabled) {
+ if (is_vg20) {
if ((pipe_fuses & (1 << i)) != 0) {
dm_error("DC: skip invalid pipe %d!\n", i);
continue;
@@ -1093,10 +1147,24 @@ static bool construct(
pool->base.pipe_count = j;
pool->base.timing_generator_count = j;
- if (!resource_construct(num_virtual_links, dc, &pool->base,
- &res_create_funcs))
+ if (is_vg20)
+ res_funcs = &dce121_res_create_funcs;
+ else
+ res_funcs = &res_create_funcs;
+
+ if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs))
goto res_create_fail;
+ /*
+ * This is a bit of a hack. The xGMI enabled info is used to determine
+ * if audio and display clocks need to be adjusted with the WAFL link's
+ * SS info. This is a responsiblity of the clk_mgr. But since MMHUB is
+ * under hwseq, and the relevant register is in MMHUB, we have to do it
+ * here.
+ */
+ if (is_vg20 && dce121_xgmi_enabled(dc->hwseq))
+ dce121_clock_patch_xgmi_ss_info(pool->base.clk_mgr);
+
/* Create hardware sequencer */
if (!dce120_hw_sequencer_create(dc))
goto controller_create_fail;
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
index cdd1d6b7b9f2..2eca81b5cf2f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
@@ -77,6 +77,7 @@
#ifndef mmBIOS_SCRATCH_2
#define mmBIOS_SCRATCH_2 0x05CB
+ #define mmBIOS_SCRATCH_3 0x05CC
#define mmBIOS_SCRATCH_6 0x05CF
#endif
@@ -358,6 +359,7 @@ static const struct dce110_clk_src_mask cs_mask = {
};
static const struct bios_registers bios_regs = {
+ .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3,
.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6
};
@@ -467,7 +469,7 @@ static struct output_pixel_processor *dce80_opp_create(
return &opp->base;
}
-struct aux_engine *dce80_aux_engine_create(
+struct dce_aux *dce80_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c
index 3ba4712a35ab..8b5ce557ee71 100644
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c
@@ -84,17 +84,17 @@ static const struct dce110_timing_generator_offsets reg_offsets[] = {
#define DCP_REG(reg) (reg + tg110->offsets.dcp)
#define DMIF_REG(reg) (reg + tg110->offsets.dmif)
-static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_khz)
+static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_100hz)
{
uint64_t pix_dur;
uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1
+ DCE110TG_FROM_TG(tg)->offsets.dmif;
uint32_t value = dm_read_reg(tg->ctx, addr);
- if (pix_clk_khz == 0)
+ if (pix_clk_100hz == 0)
return;
- pix_dur = 1000000000 / pix_clk_khz;
+ pix_dur = div_u64(10000000000ull, pix_clk_100hz);
set_reg_field_value(
value,
@@ -110,7 +110,7 @@ static void program_timing(struct timing_generator *tg,
bool use_vbios)
{
if (!use_vbios)
- program_pix_dur(tg, timing->pix_clk_khz);
+ program_pix_dur(tg, timing->pix_clk_100hz);
dce110_tg_program_timing(tg, timing, use_vbios);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
index 54abedbf1b43..afe8c42211cd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
@@ -161,69 +161,17 @@ static int get_active_display_cnt(
return display_count;
}
-static void notify_deep_sleep_dcfclk_to_smu(
- struct pp_smu_funcs_rv *pp_smu, int min_dcef_deep_sleep_clk_khz)
-{
- int min_dcef_deep_sleep_clk_mhz; //minimum required DCEF Deep Sleep clock in mhz
- /*
- * if function pointer not set up, this message is
- * sent as part of pplib_apply_display_requirements.
- * So just return.
- */
- if (!pp_smu || !pp_smu->set_min_deep_sleep_dcfclk)
- return;
-
- min_dcef_deep_sleep_clk_mhz = (min_dcef_deep_sleep_clk_khz + 999) / 1000; //Round up
- pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, min_dcef_deep_sleep_clk_mhz);
-}
-
-static void notify_hard_min_dcfclk_to_smu(
- struct pp_smu_funcs_rv *pp_smu, int min_dcf_clk_khz)
-{
- int min_dcf_clk_mhz; //minimum required DCF clock in mhz
-
- /*
- * if function pointer not set up, this message is
- * sent as part of pplib_apply_display_requirements.
- * So just return.
- */
- if (!pp_smu || !pp_smu->set_hard_min_dcfclk_by_freq)
- return;
-
- min_dcf_clk_mhz = min_dcf_clk_khz / 1000;
-
- pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, min_dcf_clk_mhz);
-}
-
-static void notify_hard_min_fclk_to_smu(
- struct pp_smu_funcs_rv *pp_smu, int min_f_clk_khz)
-{
- int min_f_clk_mhz; //minimum required F clock in mhz
-
- /*
- * if function pointer not set up, this message is
- * sent as part of pplib_apply_display_requirements.
- * So just return.
- */
- if (!pp_smu || !pp_smu->set_hard_min_fclk_by_freq)
- return;
-
- min_f_clk_mhz = min_f_clk_khz / 1000;
-
- pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, min_f_clk_mhz);
-}
-
static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
struct dc_state *context,
bool safe_to_lower)
{
struct dc *dc = clk_mgr->ctx->dc;
+ struct dc_debug_options *debug = &dc->debug;
struct dc_clocks *new_clocks = &context->bw.dcn.clk;
struct pp_smu_display_requirement_rv *smu_req_cur =
&dc->res_pool->pp_smu_req;
struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
- uint32_t requested_dcf_clock_in_khz = 0;
bool send_request_to_increase = false;
bool send_request_to_lower = false;
int display_count;
@@ -243,9 +191,8 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
*/
if (pp_smu->set_display_count)
pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
- else
- smu_req.display_count = display_count;
+ smu_req.display_count = display_count;
}
if (new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz
@@ -261,12 +208,13 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
}
// F Clock
+ if (debug->force_fclk_khz != 0)
+ new_clocks->fclk_khz = debug->force_fclk_khz;
+
if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) {
clk_mgr->clks.fclk_khz = new_clocks->fclk_khz;
smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000;
- notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz);
-
send_request_to_lower = true;
}
@@ -281,7 +229,7 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
if (should_set_clock(safe_to_lower,
new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) {
clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
- smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz / 1000;
+ smu_req.min_deep_sleep_dcefclk_mhz = (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000;
send_request_to_lower = true;
}
@@ -291,15 +239,18 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
*/
if (send_request_to_increase) {
/*use dcfclk to request voltage*/
- requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
-
- notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz);
-
- if (pp_smu->set_display_requirement)
- pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
-
- notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
- dcn1_pplib_apply_display_requirements(dc, context);
+ if (pp_smu->set_hard_min_fclk_by_freq &&
+ pp_smu->set_hard_min_dcfclk_by_freq &&
+ pp_smu->set_min_deep_sleep_dcfclk) {
+
+ pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_fclk_mhz);
+ pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_dcefclk_mhz);
+ pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, smu_req.min_deep_sleep_dcefclk_mhz);
+ } else {
+ if (pp_smu->set_display_requirement)
+ pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+ dcn1_pplib_apply_display_requirements(dc, context);
+ }
}
/* dcn1 dppclk is tied to dispclk */
@@ -314,18 +265,20 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
if (!send_request_to_increase && send_request_to_lower) {
/*use dcfclk to request voltage*/
- requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
-
- notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz);
-
- if (pp_smu->set_display_requirement)
- pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
-
- notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
- dcn1_pplib_apply_display_requirements(dc, context);
+ if (pp_smu->set_hard_min_fclk_by_freq &&
+ pp_smu->set_hard_min_dcfclk_by_freq &&
+ pp_smu->set_min_deep_sleep_dcfclk) {
+
+ pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_fclk_mhz);
+ pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_dcefclk_mhz);
+ pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, smu_req.min_deep_sleep_dcefclk_mhz);
+ } else {
+ if (pp_smu->set_display_requirement)
+ pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+ dcn1_pplib_apply_display_requirements(dc, context);
+ }
}
-
*smu_req_cur = smu_req;
}
static const struct clk_mgr_funcs dcn1_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
index dcb3c5530236..cd1ebe57ed59 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
@@ -463,7 +463,7 @@ void dpp1_set_cursor_position(
if (src_y_offset >= (int)param->viewport.height)
cur_en = 0; /* not visible beyond bottom edge*/
- if (src_y_offset < 0)
+ if (src_y_offset + (int)height <= 0)
cur_en = 0; /* not visible beyond top edge*/
REG_UPDATE(CURSOR0_CONTROL,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c
index 116977eb24e2..41f0f4c912e7 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c
@@ -51,10 +51,6 @@
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
-struct dcn10_input_csc_matrix {
- enum dc_color_space color_space;
- uint16_t regval[12];
-};
enum dcn10_coef_filter_type_sel {
SCL_COEF_LUMA_VERT_FILTER = 0,
@@ -99,7 +95,7 @@ enum gamut_remap_select {
GAMUT_REMAP_COMB_COEFF
};
-static const struct dcn10_input_csc_matrix dcn10_input_csc_matrix[] = {
+static const struct dpp_input_csc_matrix dpp_input_csc_matrix[] = {
{COLOR_SPACE_SRGB,
{0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{COLOR_SPACE_SRGB_LIMITED,
@@ -454,7 +450,7 @@ void dpp1_program_input_csc(
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
int i;
- int arr_size = sizeof(dcn10_input_csc_matrix)/sizeof(struct dcn10_input_csc_matrix);
+ int arr_size = sizeof(dpp_input_csc_matrix)/sizeof(struct dpp_input_csc_matrix);
const uint16_t *regval = NULL;
uint32_t cur_select = 0;
enum dcn10_input_csc_select select;
@@ -467,8 +463,8 @@ void dpp1_program_input_csc(
if (tbl_entry == NULL) {
for (i = 0; i < arr_size; i++)
- if (dcn10_input_csc_matrix[i].color_space == color_space) {
- regval = dcn10_input_csc_matrix[i].regval;
+ if (dpp_input_csc_matrix[i].color_space == color_space) {
+ regval = dpp_input_csc_matrix[i].regval;
break;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
index 4a863a5dab41..c7642e748297 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
@@ -597,11 +597,13 @@ static void dpp1_dscl_set_manual_ratio_init(
SCL_V_INIT_FRAC, init_frac,
SCL_V_INIT_INT, init_int);
- init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5;
- init_int = dc_fixpt_floor(data->inits.v_bot);
- REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0,
- SCL_V_INIT_FRAC_BOT, init_frac,
- SCL_V_INIT_INT_BOT, init_int);
+ if (REG(SCL_VERT_FILTER_INIT_BOT)) {
+ init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5;
+ init_int = dc_fixpt_floor(data->inits.v_bot);
+ REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0,
+ SCL_V_INIT_FRAC_BOT, init_frac,
+ SCL_V_INIT_INT_BOT, init_int);
+ }
init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5;
init_int = dc_fixpt_floor(data->inits.v_c);
@@ -609,11 +611,13 @@ static void dpp1_dscl_set_manual_ratio_init(
SCL_V_INIT_FRAC_C, init_frac,
SCL_V_INIT_INT_C, init_int);
- init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5;
- init_int = dc_fixpt_floor(data->inits.v_c_bot);
- REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0,
- SCL_V_INIT_FRAC_BOT_C, init_frac,
- SCL_V_INIT_INT_BOT_C, init_int);
+ if (REG(SCL_VERT_FILTER_INIT_BOT_C)) {
+ init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5;
+ init_int = dc_fixpt_floor(data->inits.v_c_bot);
+ REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0,
+ SCL_V_INIT_FRAC_BOT_C, init_frac,
+ SCL_V_INIT_INT_BOT_C, init_int);
+ }
}
@@ -688,15 +692,17 @@ void dpp1_dscl_set_scaler_manual_scale(
return;
/* Black offsets */
- if (ycbcr)
- REG_SET_2(SCL_BLACK_OFFSET, 0,
- SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
- SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR);
- else
+ if (REG(SCL_BLACK_OFFSET)) {
+ if (ycbcr)
+ REG_SET_2(SCL_BLACK_OFFSET, 0,
+ SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
+ SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR);
+ else
- REG_SET_2(SCL_BLACK_OFFSET, 0,
- SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
- SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y);
+ REG_SET_2(SCL_BLACK_OFFSET, 0,
+ SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
+ SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y);
+ }
/* Manually calculate scale ratio and init values */
dpp1_dscl_set_manual_ratio_init(dpp, scl_data);
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 c7d1e678ebf5..e161ad836812 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
@@ -29,19 +29,20 @@
#include "reg_helper.h"
#define CTX \
- hubbub->ctx
+ hubbub1->base.ctx
#define DC_LOGGER \
- hubbub->ctx->logger
+ hubbub1->base.ctx->logger
#define REG(reg)\
- hubbub->regs->reg
+ hubbub1->regs->reg
#undef FN
#define FN(reg_name, field_name) \
- hubbub->shifts->field_name, hubbub->masks->field_name
+ hubbub1->shifts->field_name, hubbub1->masks->field_name
void hubbub1_wm_read_state(struct hubbub *hubbub,
struct dcn_hubbub_wm *wm)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
struct dcn_hubbub_wm_set *s;
memset(wm, 0, sizeof(struct dcn_hubbub_wm));
@@ -87,14 +88,23 @@ void hubbub1_wm_read_state(struct hubbub *hubbub,
s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
}
-void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub)
+void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow)
{
- REG_UPDATE(DCHUBBUB_ARB_DRAM_STATE_CNTL,
- DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, 0);
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
+ /*
+ * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter
+ * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter
+ */
+
+ REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
+ DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
+ DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow);
}
bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
uint32_t enable = 0;
REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
@@ -107,6 +117,8 @@ bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
bool hubbub1_verify_allow_pstate_change_high(
struct hubbub *hubbub)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_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
*
@@ -193,7 +205,7 @@ bool hubbub1_verify_allow_pstate_change_high(
* 31: SOC pstate change request
*/
- REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub->debug_test_index_pstate);
+ REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub1->debug_test_index_pstate);
for (i = 0; i < pstate_wait_timeout_us; i++) {
debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
@@ -244,6 +256,8 @@ static uint32_t convert_and_clamp(
void hubbub1_wm_change_req_wa(struct hubbub *hubbub)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1);
}
@@ -254,7 +268,7 @@ void hubbub1_program_watermarks(
unsigned int refclk_mhz,
bool safe_to_lower)
{
- uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0;
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
/*
* Need to clamp to max of the register values (i.e. no wrap)
* for dcn1, all wm registers are 21-bit wide
@@ -264,8 +278,8 @@ void hubbub1_program_watermarks(
/* Repeat for water mark set A, B, C and D. */
/* clock state A */
- if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) {
- hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
+ if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
+ hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
refclk_mhz, 0x1fffff);
REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
@@ -275,20 +289,22 @@ void hubbub1_program_watermarks(
watermarks->a.urgent_ns, prog_wm_value);
}
- if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) {
- hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
- prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
- refclk_mhz, 0x1fffff);
- REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
- DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
- "HW register value = 0x%x\n",
- watermarks->a.pte_meta_urgent_ns, prog_wm_value);
+ if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) {
+ if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) {
+ hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
+ prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
+ refclk_mhz, 0x1fffff);
+ REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
+ DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
+ "HW register value = 0x%x\n",
+ watermarks->a.pte_meta_urgent_ns, prog_wm_value);
+ }
}
if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
- > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
- hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
+ > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
+ hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
@@ -300,8 +316,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
- > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) {
- hubbub->watermarks.a.cstate_pstate.cstate_exit_ns =
+ > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
+ hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
watermarks->a.cstate_pstate.cstate_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->a.cstate_pstate.cstate_exit_ns,
@@ -314,8 +330,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
- > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) {
- hubbub->watermarks.a.cstate_pstate.pstate_change_ns =
+ > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
+ hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
watermarks->a.cstate_pstate.pstate_change_ns;
prog_wm_value = convert_and_clamp(
watermarks->a.cstate_pstate.pstate_change_ns,
@@ -327,8 +343,8 @@ void hubbub1_program_watermarks(
}
/* clock state B */
- if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) {
- hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
+ if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
+ hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
refclk_mhz, 0x1fffff);
REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
@@ -338,20 +354,22 @@ void hubbub1_program_watermarks(
watermarks->b.urgent_ns, prog_wm_value);
}
- if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) {
- hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
- prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
- refclk_mhz, 0x1fffff);
- REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
- DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
- "HW register value = 0x%x\n",
- watermarks->b.pte_meta_urgent_ns, prog_wm_value);
+ if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) {
+ if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) {
+ hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
+ prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
+ refclk_mhz, 0x1fffff);
+ REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
+ DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
+ "HW register value = 0x%x\n",
+ watermarks->b.pte_meta_urgent_ns, prog_wm_value);
+ }
}
if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
- > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
- hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
+ > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
+ hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
@@ -363,8 +381,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
- > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) {
- hubbub->watermarks.b.cstate_pstate.cstate_exit_ns =
+ > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
+ hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
watermarks->b.cstate_pstate.cstate_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->b.cstate_pstate.cstate_exit_ns,
@@ -377,8 +395,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
- > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) {
- hubbub->watermarks.b.cstate_pstate.pstate_change_ns =
+ > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
+ hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
watermarks->b.cstate_pstate.pstate_change_ns;
prog_wm_value = convert_and_clamp(
watermarks->b.cstate_pstate.pstate_change_ns,
@@ -390,8 +408,8 @@ void hubbub1_program_watermarks(
}
/* clock state C */
- if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) {
- hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
+ if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
+ hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
refclk_mhz, 0x1fffff);
REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
@@ -401,20 +419,22 @@ void hubbub1_program_watermarks(
watermarks->c.urgent_ns, prog_wm_value);
}
- if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) {
- hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
- prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
- refclk_mhz, 0x1fffff);
- REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
- DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
- "HW register value = 0x%x\n",
- watermarks->c.pte_meta_urgent_ns, prog_wm_value);
+ if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) {
+ if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) {
+ hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
+ prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
+ refclk_mhz, 0x1fffff);
+ REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
+ DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
+ "HW register value = 0x%x\n",
+ watermarks->c.pte_meta_urgent_ns, prog_wm_value);
+ }
}
if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
- > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
- hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
+ > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
+ hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
@@ -426,8 +446,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
- > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) {
- hubbub->watermarks.c.cstate_pstate.cstate_exit_ns =
+ > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
+ hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
watermarks->c.cstate_pstate.cstate_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->c.cstate_pstate.cstate_exit_ns,
@@ -440,8 +460,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
- > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) {
- hubbub->watermarks.c.cstate_pstate.pstate_change_ns =
+ > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
+ hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
watermarks->c.cstate_pstate.pstate_change_ns;
prog_wm_value = convert_and_clamp(
watermarks->c.cstate_pstate.pstate_change_ns,
@@ -453,8 +473,8 @@ void hubbub1_program_watermarks(
}
/* clock state D */
- if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) {
- hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
+ if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
+ hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
refclk_mhz, 0x1fffff);
REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
@@ -464,20 +484,22 @@ void hubbub1_program_watermarks(
watermarks->d.urgent_ns, prog_wm_value);
}
- if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) {
- hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
- prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
- refclk_mhz, 0x1fffff);
- REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
- DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
- "HW register value = 0x%x\n",
- watermarks->d.pte_meta_urgent_ns, prog_wm_value);
+ if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) {
+ if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) {
+ hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
+ prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
+ refclk_mhz, 0x1fffff);
+ REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
+ DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
+ "HW register value = 0x%x\n",
+ watermarks->d.pte_meta_urgent_ns, prog_wm_value);
+ }
}
if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
- > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
- hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
+ > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
+ hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
@@ -489,8 +511,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
- > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) {
- hubbub->watermarks.d.cstate_pstate.cstate_exit_ns =
+ > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
+ hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
watermarks->d.cstate_pstate.cstate_exit_ns;
prog_wm_value = convert_and_clamp(
watermarks->d.cstate_pstate.cstate_exit_ns,
@@ -503,8 +525,8 @@ void hubbub1_program_watermarks(
}
if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
- > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) {
- hubbub->watermarks.d.cstate_pstate.pstate_change_ns =
+ > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
+ hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
watermarks->d.cstate_pstate.pstate_change_ns;
prog_wm_value = convert_and_clamp(
watermarks->d.cstate_pstate.pstate_change_ns,
@@ -520,9 +542,7 @@ void hubbub1_program_watermarks(
REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
- REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
- DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
- DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en);
+ hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
#if 0
REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
@@ -535,6 +555,8 @@ void hubbub1_update_dchub(
struct hubbub *hubbub,
struct dchub_init_data *dh_data)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) {
ASSERT(false);
/*should not come here*/
@@ -594,6 +616,8 @@ void hubbub1_update_dchub(
void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
uint32_t watermark_change_req;
REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
@@ -610,6 +634,8 @@ void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
{
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
uint32_t reset_en = reset ? 1 : 0;
REG_UPDATE(DCHUBBUB_SOFT_RESET,
@@ -752,7 +778,9 @@ static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub,
const struct dc_dcc_surface_param *input,
struct dc_surface_dcc_cap *output)
{
- struct dc *dc = hubbub->ctx->dc;
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+ struct dc *dc = hubbub1->base.ctx->dc;
+
/* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
enum dcc_control dcc_control;
unsigned int bpe;
@@ -764,10 +792,10 @@ static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub,
if (dc->debug.disable_dcc == DCC_DISABLE)
return false;
- if (!hubbub->funcs->dcc_support_pixel_format(input->format, &bpe))
+ if (!hubbub1->base.funcs->dcc_support_pixel_format(input->format, &bpe))
return false;
- if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
+ if (!hubbub1->base.funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
&segment_order_horz, &segment_order_vert))
return false;
@@ -837,6 +865,7 @@ static const struct hubbub_funcs hubbub1_funcs = {
.dcc_support_swizzle = hubbub1_dcc_support_swizzle,
.dcc_support_pixel_format = hubbub1_dcc_support_pixel_format,
.get_dcc_compression_cap = hubbub1_get_dcc_compression_cap,
+ .wm_read_state = hubbub1_wm_read_state,
};
void hubbub1_construct(struct hubbub *hubbub,
@@ -845,18 +874,20 @@ void hubbub1_construct(struct hubbub *hubbub,
const struct dcn_hubbub_shift *hubbub_shift,
const struct dcn_hubbub_mask *hubbub_mask)
{
- hubbub->ctx = ctx;
+ struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
+
+ hubbub1->base.ctx = ctx;
- hubbub->funcs = &hubbub1_funcs;
+ hubbub1->base.funcs = &hubbub1_funcs;
- hubbub->regs = hubbub_regs;
- hubbub->shifts = hubbub_shift;
- hubbub->masks = hubbub_mask;
+ hubbub1->regs = hubbub_regs;
+ hubbub1->shifts = hubbub_shift;
+ hubbub1->masks = hubbub_mask;
- hubbub->debug_test_index_pstate = 0x7;
+ hubbub1->debug_test_index_pstate = 0x7;
#if defined(CONFIG_DRM_AMD_DC_DCN1_01)
if (ctx->dce_version == DCN_VERSION_1_01)
- hubbub->debug_test_index_pstate = 0xB;
+ hubbub1->debug_test_index_pstate = 0xB;
#endif
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
index d0f03d152913..9cd4a5194154 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
@@ -29,6 +29,9 @@
#include "core_types.h"
#include "dchubbub.h"
+#define TO_DCN10_HUBBUB(hubbub)\
+ container_of(hubbub, struct dcn10_hubbub, base)
+
#define HUBHUB_REG_LIST_DCN()\
SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A),\
SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A),\
@@ -107,6 +110,12 @@ struct dcn_hubbub_registers {
uint32_t DCHUBBUB_SDPIF_AGP_TOP;
uint32_t DCHUBBUB_CRC_CTRL;
uint32_t DCHUBBUB_SOFT_RESET;
+ uint32_t DCN_VM_FB_LOCATION_BASE;
+ uint32_t DCN_VM_FB_LOCATION_TOP;
+ uint32_t DCN_VM_FB_OFFSET;
+ uint32_t DCN_VM_AGP_BOT;
+ uint32_t DCN_VM_AGP_TOP;
+ uint32_t DCN_VM_AGP_BASE;
};
/* set field name */
@@ -152,7 +161,13 @@ struct dcn_hubbub_registers {
type SDPIF_FB_OFFSET;\
type SDPIF_AGP_BASE;\
type SDPIF_AGP_BOT;\
- type SDPIF_AGP_TOP
+ type SDPIF_AGP_TOP;\
+ type FB_BASE;\
+ type FB_TOP;\
+ type FB_OFFSET;\
+ type AGP_BOT;\
+ type AGP_TOP;\
+ type AGP_BASE
struct dcn_hubbub_shift {
@@ -165,22 +180,8 @@ struct dcn_hubbub_mask {
struct dc;
-struct dcn_hubbub_wm_set {
- uint32_t wm_set;
- uint32_t data_urgent;
- uint32_t pte_meta_urgent;
- uint32_t sr_enter;
- uint32_t sr_exit;
- uint32_t dram_clk_chanage;
-};
-
-struct dcn_hubbub_wm {
- struct dcn_hubbub_wm_set sets[4];
-};
-
-struct hubbub {
- const struct hubbub_funcs *funcs;
- struct dc_context *ctx;
+struct dcn10_hubbub {
+ struct hubbub base;
const struct dcn_hubbub_registers *regs;
const struct dcn_hubbub_shift *shifts;
const struct dcn_hubbub_mask *masks;
@@ -203,7 +204,7 @@ void hubbub1_program_watermarks(
unsigned int refclk_mhz,
bool safe_to_lower);
-void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub);
+void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow);
bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubub);
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 345af015d061..683829466a44 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
@@ -115,7 +115,7 @@ static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank)
REG_UPDATE(DCHUBP_CNTL, HUBP_BLANK_EN, blank_en);
}
-static void hubp1_vready_workaround(struct hubp *hubp,
+void hubp1_vready_workaround(struct hubp *hubp,
struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest)
{
uint32_t value = 0;
@@ -317,7 +317,8 @@ void hubp1_program_pixel_format(
bool hubp1_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ uint8_t vmid)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
@@ -1140,7 +1141,7 @@ void hubp1_cursor_set_position(
if (src_y_offset >= (int)param->viewport.height)
cur_en = 0; /* not visible beyond bottom edge*/
- if (src_y_offset < 0) //+ (int)hubp->curs_attr.height
+ if (src_y_offset + (int)hubp->curs_attr.height <= 0)
cur_en = 0; /* not visible beyond top edge*/
if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0)
@@ -1149,9 +1150,28 @@ void hubp1_cursor_set_position(
REG_UPDATE(CURSOR_CONTROL,
CURSOR_ENABLE, cur_en);
- REG_SET_2(CURSOR_POSITION, 0,
- CURSOR_X_POSITION, pos->x,
+ //account for cases where we see negative offset relative to overlay plane
+ if (src_x_offset < 0 && src_y_offset < 0) {
+ REG_SET_2(CURSOR_POSITION, 0,
+ CURSOR_X_POSITION, 0,
+ CURSOR_Y_POSITION, 0);
+ x_hotspot -= src_x_offset;
+ y_hotspot -= src_y_offset;
+ } else if (src_x_offset < 0) {
+ REG_SET_2(CURSOR_POSITION, 0,
+ CURSOR_X_POSITION, 0,
CURSOR_Y_POSITION, pos->y);
+ x_hotspot -= src_x_offset;
+ } else if (src_y_offset < 0) {
+ REG_SET_2(CURSOR_POSITION, 0,
+ CURSOR_X_POSITION, pos->x,
+ CURSOR_Y_POSITION, 0);
+ y_hotspot -= src_y_offset;
+ } else {
+ REG_SET_2(CURSOR_POSITION, 0,
+ CURSOR_X_POSITION, pos->x,
+ CURSOR_Y_POSITION, pos->y);
+ }
REG_SET_2(CURSOR_HOT_SPOT, 0,
CURSOR_HOT_SPOT_X, x_hotspot,
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 62d4232e7796..a6d6dfe00617 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
@@ -707,11 +707,6 @@ void hubp1_dcc_control(struct hubp *hubp,
bool enable,
bool independent_64b_blks);
-bool hubp1_program_surface_flip_and_addr(
- struct hubp *hubp,
- const struct dc_plane_address *address,
- bool flip_immediate);
-
bool hubp1_is_flip_pending(struct hubp *hubp);
void hubp1_cursor_set_attributes(
@@ -745,5 +740,7 @@ void hubp1_clear_underflow(struct hubp *hubp);
enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch);
+void hubp1_vready_workaround(struct hubp *hubp,
+ struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest);
#endif
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 91e015e14355..117d9d8227f7 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
@@ -40,7 +40,6 @@
#include "ipp.h"
#include "mpc.h"
#include "reg_helper.h"
-#include "custom_float.h"
#include "dcn10_hubp.h"
#include "dcn10_hubbub.h"
#include "dcn10_cm_common.h"
@@ -92,10 +91,11 @@ static void log_mpc_crc(struct dc *dc,
void dcn10_log_hubbub_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx)
{
struct dc_context *dc_ctx = dc->ctx;
- struct dcn_hubbub_wm wm = {0};
+ struct dcn_hubbub_wm wm;
int i;
- hubbub1_wm_read_state(dc->res_pool->hubbub, &wm);
+ memset(&wm, 0, sizeof(struct dcn_hubbub_wm));
+ dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm);
DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent"
" sr_enter sr_exit dram_clk_change\n");
@@ -636,8 +636,6 @@ static enum dc_status dcn10_enable_stream_timing(
struct dc_stream_state *stream = pipe_ctx->stream;
enum dc_color_space color_space;
struct tg_color black_color = {0};
- struct drr_params params = {0};
- unsigned int event_triggers = 0;
/* by upper caller loop, pipe0 is parent pipe and be called first.
* back end is set up by for pipe0. Other children pipe share back end
@@ -705,19 +703,6 @@ static enum dc_status dcn10_enable_stream_timing(
return DC_ERROR_UNEXPECTED;
}
- params.vertical_total_min = stream->adjust.v_total_min;
- params.vertical_total_max = stream->adjust.v_total_max;
- if (pipe_ctx->stream_res.tg->funcs->set_drr)
- pipe_ctx->stream_res.tg->funcs->set_drr(
- pipe_ctx->stream_res.tg, &params);
-
- // DRR should set trigger event to monitor surface update event
- if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
- event_triggers = 0x80;
- if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
- pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
- pipe_ctx->stream_res.tg, event_triggers);
-
/* TODO program crtc source select for non-virtual signal*/
/* TODO program FMT */
/* TODO setup link_enc */
@@ -971,92 +956,34 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->pipe_idx);
}
-static void dcn10_init_hw(struct dc *dc)
+static void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
{
int i;
- struct abm *abm = dc->res_pool->abm;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- struct dce_hwseq *hws = dc->hwseq;
- struct dc_bios *dcb = dc->ctx->dc_bios;
- struct dc_state *context = dc->current_state;
-
- if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- REG_WRITE(REFCLK_CNTL, 0);
- REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
- REG_WRITE(DIO_MEM_PWR_CTRL, 0);
-
- if (!dc->debug.disable_clock_gate) {
- /* enable all DCN clock gating */
- REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
-
- REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
-
- REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
- }
-
- enable_power_gating_plane(dc->hwseq, true);
- } else {
-
- if (!dcb->funcs->is_accelerated_mode(dcb)) {
- bool allow_self_fresh_force_enable =
- hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub);
-
- bios_golden_init(dc);
-
- /* WA for making DF sleep when idle after resume from S0i3.
- * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by
- * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0
- * before calling command table and it changed to 1 after,
- * it should be set back to 0.
- */
- if (allow_self_fresh_force_enable == false &&
- hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub))
- hubbub1_disable_allow_self_refresh(dc->res_pool->hubbub);
-
- disable_vga(dc->hwseq);
- }
-
- for (i = 0; i < dc->link_count; i++) {
- /* Power up AND update implementation according to the
- * required signal (which may be different from the
- * default signal on connector).
- */
- struct dc_link *link = dc->links[i];
-
- if (link->link_enc->connector.id == CONNECTOR_ID_EDP)
- dc->hwss.edp_power_control(link, true);
-
- link->link_enc->funcs->hw_init(link->link_enc);
- }
- }
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->lock(tg);
- }
-
- /* Blank controller using driver code instead of
- * command table.
- */
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct timing_generator *tg = dc->res_pool->timing_generators[i];
+ /* Blank controller using driver code instead of
+ * command table.
+ */
if (tg->funcs->is_tg_enabled(tg)) {
tg->funcs->set_blank(tg, true);
hwss_wait_for_blank_complete(tg);
}
}
- /* Reset all MPCC muxes */
dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc);
- for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
struct hubp *hubp = dc->res_pool->hubps[i];
struct dpp *dpp = dc->res_pool->dpps[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ dpp->funcs->dpp_reset(dpp);
pipe_ctx->stream_res.tg = tg;
pipe_ctx->pipe_idx = i;
@@ -1074,18 +1001,9 @@ static void dcn10_init_hw(struct dc *dc)
pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
hwss1_plane_atomic_disconnect(dc, pipe_ctx);
- }
-
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->unlock(tg);
- }
-
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct timing_generator *tg = dc->res_pool->timing_generators[i];
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
dcn10_disable_plane(dc, pipe_ctx);
@@ -1094,10 +1012,73 @@ static void dcn10_init_hw(struct dc *dc)
tg->funcs->tg_init(tg);
}
+}
- /* end of FPGA. Below if real ASIC */
- if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+static void dcn10_init_hw(struct dc *dc)
+{
+ int i;
+ struct abm *abm = dc->res_pool->abm;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ struct dce_hwseq *hws = dc->hwseq;
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ REG_WRITE(REFCLK_CNTL, 0);
+ REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
+ REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+
+ if (!dc->debug.disable_clock_gate) {
+ /* enable all DCN clock gating */
+ REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
+
+ REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
+
+ REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
+ }
+
+ enable_power_gating_plane(dc->hwseq, true);
+
+ /* end of FPGA. Below if real ASIC */
return;
+ }
+
+ if (!dcb->funcs->is_accelerated_mode(dcb)) {
+ bool allow_self_fresh_force_enable =
+ hububu1_is_allow_self_refresh_enabled(
+ dc->res_pool->hubbub);
+
+ bios_golden_init(dc);
+
+ /* WA for making DF sleep when idle after resume from S0i3.
+ * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by
+ * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0
+ * before calling command table and it changed to 1 after,
+ * it should be set back to 0.
+ */
+ if (allow_self_fresh_force_enable == false &&
+ hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub))
+ hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true);
+
+ disable_vga(dc->hwseq);
+ }
+
+ for (i = 0; i < dc->link_count; i++) {
+ /* Power up AND update implementation according to the
+ * required signal (which may be different from the
+ * default signal on connector).
+ */
+ struct dc_link *link = dc->links[i];
+
+ if (link->link_enc->connector.id == CONNECTOR_ID_EDP)
+ dc->hwss.edp_power_control(link, true);
+
+ link->link_enc->funcs->hw_init(link->link_enc);
+
+ /* 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_status.link_active = true;
+ }
for (i = 0; i < dc->res_pool->audio_count; i++) {
struct audio *audio = dc->res_pool->audios[i];
@@ -1128,6 +1109,9 @@ static void dcn10_init_hw(struct dc *dc)
enable_power_gating_plane(dc->hwseq, true);
memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks));
+
+ if (dc->hwss.init_pipes)
+ dc->hwss.init_pipes(dc, dc->current_state);
}
static void reset_hw_ctx_wrap(
@@ -1202,7 +1186,8 @@ static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_c
pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
pipe_ctx->plane_res.hubp,
&plane_state->address,
- plane_state->flip_immediate);
+ plane_state->flip_immediate,
+ 0);
plane_state->status.requested_address = plane_state->address;
@@ -2048,7 +2033,7 @@ void update_dchubp_dpp(
dc->res_pool->dccg->funcs->update_dpp_dto(
dc->res_pool->dccg,
dpp->inst,
- pipe_ctx->plane_res.bw.calc.dppclk_khz);
+ pipe_ctx->plane_res.bw.dppclk_khz);
else
dc->res_pool->clk_mgr->clks.dppclk_khz = should_divided_by_2 ?
dc->res_pool->clk_mgr->clks.dispclk_khz / 2 :
@@ -2125,7 +2110,8 @@ void update_dchubp_dpp(
plane_state->update_flags.bits.swizzle_change ||
plane_state->update_flags.bits.dcc_change ||
plane_state->update_flags.bits.bpp_change ||
- plane_state->update_flags.bits.scaling_change) {
+ plane_state->update_flags.bits.scaling_change ||
+ plane_state->update_flags.bits.plane_size_change) {
hubp->funcs->hubp_program_surface_config(
hubp,
plane_state->format,
@@ -2252,13 +2238,11 @@ static void program_all_pipe_in_tree(
}
- if (pipe_ctx->plane_state != NULL) {
+ if (pipe_ctx->plane_state != NULL)
dcn10_program_pipe(dc, pipe_ctx, context);
- }
- if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) {
+ if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx)
program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
- }
}
struct pipe_ctx *find_top_pipe_for_stream(
@@ -2334,9 +2318,10 @@ static void dcn10_apply_ctx_for_surface(
}
}
- if (!pipe_ctx->plane_state &&
- old_pipe_ctx->plane_state &&
- old_pipe_ctx->stream_res.tg == tg) {
+ if ((!pipe_ctx->plane_state ||
+ pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) &&
+ old_pipe_ctx->plane_state &&
+ old_pipe_ctx->stream_res.tg == tg) {
dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx);
removed_pipe[i] = true;
@@ -2355,29 +2340,22 @@ static void dcn10_apply_ctx_for_surface(
top_pipe_to_program->plane_state->update_flags.bits.full_update)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
+ tg = pipe_ctx->stream_res.tg;
/* Skip inactive pipes and ones already updated */
if (!pipe_ctx->stream || pipe_ctx->stream == stream
- || !pipe_ctx->plane_state)
+ || !pipe_ctx->plane_state
+ || !tg->funcs->is_tg_enabled(tg))
continue;
- pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
+ tg->funcs->lock(tg);
pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent(
pipe_ctx->plane_res.hubp,
&pipe_ctx->dlg_regs,
&pipe_ctx->ttu_regs);
- }
-
- 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->stream == stream
- || !pipe_ctx->plane_state)
- continue;
- dcn10_pipe_control_lock(dc, pipe_ctx, false);
- }
+ tg->funcs->unlock(tg);
+ }
if (num_planes == 0)
false_optc_underflow_wa(dc, stream, tg);
@@ -2390,6 +2368,22 @@ static void dcn10_apply_ctx_for_surface(
hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
}
+static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context)
+{
+ uint8_t i;
+
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->streams[i]->timing.timing_3d_format
+ == TIMING_3D_FORMAT_HW_FRAME_PACKING) {
+ /*
+ * Disable stutter
+ */
+ hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false);
+ break;
+ }
+ }
+}
+
static void dcn10_prepare_bandwidth(
struct dc *dc,
struct dc_state *context)
@@ -2411,6 +2405,7 @@ static void dcn10_prepare_bandwidth(
&context->bw.dcn.watermarks,
dc->res_pool->ref_clock_inKhz / 1000,
true);
+ dcn10_stereo_hw_frame_pack_wa(dc, context);
if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
dcn_bw_notify_pplib_of_wm_ranges(dc);
@@ -2440,6 +2435,7 @@ static void dcn10_optimize_bandwidth(
&context->bw.dcn.watermarks,
dc->res_pool->ref_clock_inKhz / 1000,
true);
+ dcn10_stereo_hw_frame_pack_wa(dc, context);
if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
dcn_bw_notify_pplib_of_wm_ranges(dc);
@@ -2525,7 +2521,7 @@ static void dcn10_config_stereo_parameters(
timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
enum display_dongle_type dongle = \
- stream->sink->link->ddc->dongle_type;
+ stream->link->ddc->dongle_type;
if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
@@ -2656,7 +2652,7 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
struct dc_cursor_mi_param param = {
- .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz,
+ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz,
.viewport = pipe_ctx->plane_res.scl_data.viewport,
.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
@@ -2716,6 +2712,7 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
static const struct hw_sequencer_funcs dcn10_funcs = {
.program_gamut_remap = program_gamut_remap,
.init_hw = dcn10_init_hw,
+ .init_pipes = dcn10_init_pipes,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
.update_plane_addr = dcn10_update_plane_addr,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
index cd469014baa3..98f41d250978 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
@@ -40,7 +40,6 @@
#include "ipp.h"
#include "mpc.h"
#include "reg_helper.h"
-#include "custom_float.h"
#include "dcn10_hubp.h"
#include "dcn10_hubbub.h"
#include "dcn10_cm_common.h"
@@ -72,7 +71,7 @@ static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt,
static unsigned int dcn10_get_hubbub_state(struct dc *dc, char *pBuf, unsigned int bufSize)
{
struct dc_context *dc_ctx = dc->ctx;
- struct dcn_hubbub_wm wm = {0};
+ struct dcn_hubbub_wm wm;
int i;
unsigned int chars_printed = 0;
@@ -81,7 +80,8 @@ static unsigned int dcn10_get_hubbub_state(struct dc *dc, char *pBuf, unsigned i
const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clock_inKhz / 1000;
static const unsigned int frac = 1000;
- hubbub1_wm_read_state(dc->res_pool->hubbub, &wm);
+ memset(&wm, 0, sizeof(struct dcn_hubbub_wm));
+ dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm);
chars_printed = snprintf_count(pBuf, remaining_buffer, "wm_set_index,data_urgent,pte_meta_urgent,sr_enter,sr_exit,dram_clk_chanage\n");
remaining_buffer -= chars_printed;
@@ -419,20 +419,22 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int
unsigned int remaining_buffer = bufSize;
chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,v_bs,v_be,v_ss,v_se,vpol,vmax,vmin,vmax_sel,vmin_sel,"
- "h_bs,h_be,h_ss,h_se,hpol,htot,vtot,underflow\n");
+ "h_bs,h_be,h_ss,h_se,hpol,htot,vtot,underflow,pixelclk[khz]\n");
remaining_buffer -= chars_printed;
pBuf += chars_printed;
for (i = 0; i < pool->timing_generator_count; i++) {
struct timing_generator *tg = pool->timing_generators[i];
struct dcn_otg_state s = {0};
+ int pix_clk = 0;
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+ pix_clk = dc->current_state->res_ctx.pipe_ctx[i].stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
//only print if OTG master is enabled
if (s.otg_enabled & 1) {
chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
- "%d,%d,%d,%d,%d,%d,%d,%d"
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d"
"\n",
tg->inst,
s.v_blank_start,
@@ -451,7 +453,8 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int
s.h_sync_a_pol,
s.h_total,
s.v_total,
- s.underflow_occurred_status);
+ s.underflow_occurred_status,
+ pix_clk);
remaining_buffer -= chars_printed;
pBuf += chars_printed;
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 477ab9222216..a9db372688ff 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
@@ -85,6 +85,7 @@ static const struct link_encoder_funcs dcn10_lnk_enc_funcs = {
.enable_hpd = dcn10_link_encoder_enable_hpd,
.disable_hpd = dcn10_link_encoder_disable_hpd,
.is_dig_enabled = dcn10_is_dig_enabled,
+ .get_dig_frontend = dcn10_get_dig_frontend,
.destroy = dcn10_link_encoder_destroy
};
@@ -440,7 +441,7 @@ static uint8_t get_frontend_source(
}
}
-void configure_encoder(
+void enc1_configure_encoder(
struct dcn10_link_encoder *enc10,
const struct dc_link_settings *link_settings)
{
@@ -495,6 +496,15 @@ bool dcn10_is_dig_enabled(struct link_encoder *enc)
return value;
}
+unsigned int dcn10_get_dig_frontend(struct link_encoder *enc)
+{
+ struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+ uint32_t value;
+
+ REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value);
+ return value;
+}
+
static void link_encoder_disable(struct dcn10_link_encoder *enc10)
{
/* reset training pattern */
@@ -543,12 +553,12 @@ bool dcn10_link_encoder_validate_dvi_output(
if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) &&
signal != SIGNAL_TYPE_HDMI_TYPE_A &&
- crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK)
+ crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+ if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz > max_pixel_clock)
+ if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10))
return false;
/* DVI supports 6/8bpp single-link and 10/16bpp dual-link */
@@ -571,7 +581,7 @@ bool dcn10_link_encoder_validate_dvi_output(
static bool dcn10_link_encoder_validate_hdmi_output(
const struct dcn10_link_encoder *enc10,
const struct dc_crtc_timing *crtc_timing,
- int adjusted_pix_clk_khz)
+ int adjusted_pix_clk_100hz)
{
enum dc_color_depth max_deep_color =
enc10->base.features.max_hdmi_deep_color;
@@ -581,11 +591,11 @@ static bool dcn10_link_encoder_validate_hdmi_output(
if (crtc_timing->display_color_depth < COLOR_DEPTH_888)
return false;
- if (adjusted_pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+ if (adjusted_pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10))
return false;
- if ((adjusted_pix_clk_khz == 0) ||
- (adjusted_pix_clk_khz > enc10->base.features.max_hdmi_pixel_clock))
+ if ((adjusted_pix_clk_100hz == 0) ||
+ (adjusted_pix_clk_100hz > (enc10->base.features.max_hdmi_pixel_clock * 10)))
return false;
/* DCE11 HW does not support 420 */
@@ -594,7 +604,7 @@ static bool dcn10_link_encoder_validate_hdmi_output(
return false;
if (!enc10->base.features.flags.bits.HDMI_6GB_EN &&
- adjusted_pix_clk_khz >= 300000)
+ adjusted_pix_clk_100hz >= 3000000)
return false;
if (enc10->base.ctx->dc->debug.hdmi20_disable &&
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
@@ -738,7 +748,7 @@ bool dcn10_link_encoder_validate_output_with_stream(
case SIGNAL_TYPE_DVI_DUAL_LINK:
is_valid = dcn10_link_encoder_validate_dvi_output(
enc10,
- stream->sink->link->connector_signal,
+ stream->link->connector_signal,
stream->signal,
&stream->timing);
break;
@@ -746,7 +756,7 @@ bool dcn10_link_encoder_validate_output_with_stream(
is_valid = dcn10_link_encoder_validate_hdmi_output(
enc10,
&stream->timing,
- stream->phy_pix_clk);
+ stream->phy_pix_clk * 10);
break;
case SIGNAL_TYPE_DISPLAY_PORT:
case SIGNAL_TYPE_DISPLAY_PORT_MST:
@@ -910,7 +920,7 @@ void dcn10_link_encoder_enable_dp_output(
* but it's not passed to asic_control.
* We need to set number of lanes manually.
*/
- configure_encoder(enc10, link_settings);
+ enc1_configure_encoder(enc10, link_settings);
cntl.action = TRANSMITTER_CONTROL_ENABLE;
cntl.engine_id = enc->preferred_engine;
@@ -949,7 +959,7 @@ void dcn10_link_encoder_enable_dp_mst_output(
* but it's not passed to asic_control.
* We need to set number of lanes manually.
*/
- configure_encoder(enc10, link_settings);
+ enc1_configure_encoder(enc10, link_settings);
cntl.action = TRANSMITTER_CONTROL_ENABLE;
cntl.engine_id = ENGINE_ID_UNKNOWN;
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 49ead12b2532..b74b80a247ec 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
@@ -271,7 +271,7 @@ void dcn10_link_encoder_setup(
struct link_encoder *enc,
enum signal_type signal);
-void configure_encoder(
+void enc1_configure_encoder(
struct dcn10_link_encoder *enc10,
const struct dc_link_settings *link_settings);
@@ -336,6 +336,8 @@ void dcn10_psr_program_secondary_packet(struct link_encoder *enc,
bool dcn10_is_dig_enabled(struct link_encoder *enc);
+unsigned int dcn10_get_dig_frontend(struct link_encoder *enc);
+
void dcn10_aux_initialize(struct dcn10_link_encoder *enc10);
#endif /* __DC_LINK_ENCODER__DCN10_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
index 7c138615f17d..2f78a84f0dcb 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -97,6 +97,7 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c
struct dc_crtc_timing patched_crtc_timing;
int vesa_sync_start;
int asic_blank_end;
+ int interlace_factor;
int vertical_line_start;
patched_crtc_timing = *dc_crtc_timing;
@@ -110,13 +111,16 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c
vesa_sync_start -
patched_crtc_timing.h_border_left;
+ interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
+
vesa_sync_start = patched_crtc_timing.v_addressable +
patched_crtc_timing.v_border_bottom +
patched_crtc_timing.v_front_porch;
asic_blank_end = (patched_crtc_timing.v_total -
vesa_sync_start -
- patched_crtc_timing.v_border_top);
+ patched_crtc_timing.v_border_top)
+ * interlace_factor;
vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
if (vertical_line_start < 0) {
@@ -127,40 +131,95 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c
return vertical_line_start;
}
-void optc1_program_vline_interrupt(
+static void calc_vline_position(
struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing,
- unsigned long long vsync_delta)
+ unsigned long long vsync_delta,
+ uint32_t *start_line,
+ uint32_t *end_line)
{
-
- struct optc *optc1 = DCN10TG_FROM_TG(optc);
-
unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000);
- unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_khz + 99), 100);
+ unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_100hz + 999), 1000);
uint32_t req_delta_lines = (uint32_t) div64_u64(
(req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1),
dc_crtc_timing->h_total);
uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing);
- uint32_t start_line = 0;
- uint32_t endLine = 0;
if (req_delta_lines != 0)
- req_delta_lines--;
+ req_delta_lines--;
- if (req_delta_lines > vsync_line)
- start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) + 2;
- else
- start_line = vsync_line - req_delta_lines;
+ if (req_delta_lines > vsync_line)
+ *start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1;
+ else
+ *start_line = vsync_line - req_delta_lines;
+
+ *end_line = *start_line + 2;
+
+ if (*end_line >= dc_crtc_timing->v_total)
+ *end_line = 2;
+}
+
+void optc1_program_vline_interrupt(
+ struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing,
+ enum vline_select vline,
+ const union vline_config *vline_config)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t start_line = 0;
+ uint32_t end_line = 0;
+
+ switch (vline) {
+ case VLINE0:
+ calc_vline_position(optc, dc_crtc_timing, vline_config->delta_in_ns, &start_line, &end_line);
+ REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
+ OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
+ OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
+ break;
+ case VLINE1:
+ REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
+ OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->line_number);
+ break;
+ default:
+ break;
+ }
+}
+
+void optc1_program_vupdate_interrupt(
+ struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ int32_t vertical_line_start;
+ uint32_t asic_blank_end;
+ uint32_t vesa_sync_start;
+ struct dc_crtc_timing patched_crtc_timing;
+
+ patched_crtc_timing = *dc_crtc_timing;
+ optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
+
+ /* asic_h_blank_end = HsyncWidth + HbackPorch =
+ * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart -
+ * vesa.h_left_border
+ */
+ vesa_sync_start = patched_crtc_timing.h_addressable +
+ patched_crtc_timing.h_border_right +
+ patched_crtc_timing.h_front_porch;
- endLine = start_line + 2;
+ asic_blank_end = patched_crtc_timing.h_total -
+ vesa_sync_start -
+ patched_crtc_timing.h_border_left;
- if (endLine >= dc_crtc_timing->v_total)
- endLine = 2;
+ /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt,
+ * program the reg for interrupt postition.
+ */
+ vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
+ if (vertical_line_start < 0)
+ vertical_line_start = 0;
- REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
- OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
- OTG_VERTICAL_INTERRUPT0_LINE_END, endLine);
+ REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
+ OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
}
/**
@@ -265,22 +324,14 @@ void optc1_program_timing(
patched_crtc_timing.v_addressable +
patched_crtc_timing.v_border_bottom);
- REG_UPDATE_2(OTG_V_BLANK_START_END,
- OTG_V_BLANK_START, asic_blank_start,
- OTG_V_BLANK_END, asic_blank_end);
-
- /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt,
- * program the reg for interrupt postition.
- */
vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
v_fp2 = 0;
if (vertical_line_start < 0)
v_fp2 = -vertical_line_start;
- if (vertical_line_start < 0)
- vertical_line_start = 0;
- REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
- OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
+ REG_UPDATE_2(OTG_V_BLANK_START_END,
+ OTG_V_BLANK_START, asic_blank_start,
+ OTG_V_BLANK_END, asic_blank_end);
/* v_sync polarity */
v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ?
@@ -299,16 +350,17 @@ void optc1_program_timing(
}
/* Interlace */
- if (patched_crtc_timing.flags.INTERLACE == 1) {
- REG_UPDATE(OTG_INTERLACE_CONTROL,
- OTG_INTERLACE_ENABLE, 1);
- v_init = v_init / 2;
- if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end)
- v_fp2 = v_fp2 / 2;
- } else
- REG_UPDATE(OTG_INTERLACE_CONTROL,
- OTG_INTERLACE_ENABLE, 0);
-
+ if (REG(OTG_INTERLACE_CONTROL)) {
+ if (patched_crtc_timing.flags.INTERLACE == 1) {
+ REG_UPDATE(OTG_INTERLACE_CONTROL,
+ OTG_INTERLACE_ENABLE, 1);
+ v_init = v_init / 2;
+ if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end)
+ v_fp2 = v_fp2 / 2;
+ } else
+ REG_UPDATE(OTG_INTERLACE_CONTROL,
+ OTG_INTERLACE_ENABLE, 0);
+ }
/* VTG enable set to 0 first VInit */
REG_UPDATE(CONTROL,
@@ -338,7 +390,7 @@ void optc1_program_timing(
h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
- OTG_H_TIMING_DIV_BY2, h_div_2);
+ OTG_H_TIMING_DIV_BY2, h_div_2 || optc1->comb_opp_id != 0xf);
}
@@ -1184,6 +1236,64 @@ bool optc1_is_stereo_left_eye(struct timing_generator *optc)
return ret;
}
+bool optc1_is_matching_timing(struct timing_generator *tg,
+ const struct dc_crtc_timing *otg_timing)
+{
+ struct dc_crtc_timing hw_crtc_timing = {0};
+ struct dcn_otg_state s = {0};
+
+ if (tg == NULL || otg_timing == NULL)
+ return false;
+
+ optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+
+ hw_crtc_timing.h_total = s.h_total + 1;
+ hw_crtc_timing.h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
+ hw_crtc_timing.h_front_porch = s.h_total + 1 - s.h_blank_start;
+ hw_crtc_timing.h_sync_width = s.h_sync_a_end - s.h_sync_a_start;
+
+ hw_crtc_timing.v_total = s.v_total + 1;
+ hw_crtc_timing.v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end);
+ hw_crtc_timing.v_front_porch = s.v_total + 1 - s.v_blank_start;
+ hw_crtc_timing.v_sync_width = s.v_sync_a_end - s.v_sync_a_start;
+
+ if (otg_timing->h_total != hw_crtc_timing.h_total)
+ return false;
+
+ if (otg_timing->h_border_left != hw_crtc_timing.h_border_left)
+ return false;
+
+ if (otg_timing->h_addressable != hw_crtc_timing.h_addressable)
+ return false;
+
+ if (otg_timing->h_border_right != hw_crtc_timing.h_border_right)
+ return false;
+
+ if (otg_timing->h_front_porch != hw_crtc_timing.h_front_porch)
+ return false;
+
+ if (otg_timing->h_sync_width != hw_crtc_timing.h_sync_width)
+ return false;
+
+ if (otg_timing->v_total != hw_crtc_timing.v_total)
+ return false;
+
+ if (otg_timing->v_border_top != hw_crtc_timing.v_border_top)
+ return false;
+
+ if (otg_timing->v_addressable != hw_crtc_timing.v_addressable)
+ return false;
+
+ if (otg_timing->v_border_bottom != hw_crtc_timing.v_border_bottom)
+ return false;
+
+ if (otg_timing->v_sync_width != hw_crtc_timing.v_sync_width)
+ return false;
+
+ return true;
+}
+
+
void optc1_read_otg_state(struct optc *optc1,
struct dcn_otg_state *s)
{
@@ -1371,6 +1481,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.program_vline_interrupt = optc1_program_vline_interrupt,
+ .program_vupdate_interrupt = optc1_program_vupdate_interrupt,
.program_global_sync = optc1_program_global_sync,
.enable_crtc = optc1_enable_crtc,
.disable_crtc = optc1_disable_crtc,
@@ -1380,6 +1491,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.get_frame_count = optc1_get_vblank_counter,
.get_scanoutpos = optc1_get_crtc_scanoutpos,
.get_otg_active_size = optc1_get_otg_active_size,
+ .is_matching_timing = optc1_is_matching_timing,
.set_early_control = optc1_set_early_control,
/* used by enable_timing_synchronization. Not need for FPGA */
.wait_for_state = optc1_wait_for_state,
@@ -1419,10 +1531,13 @@ void dcn10_timing_generator_init(struct optc *optc1)
optc1->min_v_blank_interlace = 5;
optc1->min_h_sync_width = 8;
optc1->min_v_sync_width = 1;
+ optc1->comb_opp_id = 0xf;
}
bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
{
- return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
+ bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
+
+ return two_pix;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
index 8bacf0b6e27e..24452f11c598 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
@@ -67,6 +67,8 @@
SRI(OTG_CLOCK_CONTROL, OTG, inst),\
SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\
SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\
+ SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\
+ SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\
SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\
SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\
SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\
@@ -135,6 +137,8 @@ struct dcn_optc_registers {
uint32_t OTG_CLOCK_CONTROL;
uint32_t OTG_VERTICAL_INTERRUPT0_CONTROL;
uint32_t OTG_VERTICAL_INTERRUPT0_POSITION;
+ uint32_t OTG_VERTICAL_INTERRUPT1_CONTROL;
+ uint32_t OTG_VERTICAL_INTERRUPT1_POSITION;
uint32_t OTG_VERTICAL_INTERRUPT2_CONTROL;
uint32_t OTG_VERTICAL_INTERRUPT2_POSITION;
uint32_t OPTC_INPUT_CLOCK_CONTROL;
@@ -227,6 +231,8 @@ struct dcn_optc_registers {
SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\
SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\
SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\
+ SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\
+ SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\
SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\
SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\
SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\
@@ -361,6 +367,8 @@ struct dcn_optc_registers {
type OTG_VERTICAL_INTERRUPT0_INT_ENABLE;\
type OTG_VERTICAL_INTERRUPT0_LINE_START;\
type OTG_VERTICAL_INTERRUPT0_LINE_END;\
+ type OTG_VERTICAL_INTERRUPT1_INT_ENABLE;\
+ type OTG_VERTICAL_INTERRUPT1_LINE_START;\
type OTG_VERTICAL_INTERRUPT2_INT_ENABLE;\
type OTG_VERTICAL_INTERRUPT2_LINE_START;\
type OPTC_INPUT_CLK_EN;\
@@ -427,7 +435,7 @@ struct optc {
const struct dcn_optc_shift *tg_shift;
const struct dcn_optc_mask *tg_mask;
- enum controller_id controller_id;
+ int comb_opp_id;
uint32_t max_h_total;
uint32_t max_v_total;
@@ -475,9 +483,11 @@ void optc1_program_timing(
const struct dc_crtc_timing *dc_crtc_timing,
bool use_vbios);
-void optc1_program_vline_interrupt(struct timing_generator *optc,
+void optc1_program_vline_interrupt(
+ struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing,
- unsigned long long vsync_delta);
+ enum vline_select vline,
+ const union vline_config *vline_config);
void optc1_program_global_sync(
struct timing_generator *optc);
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 5d4772dec0ba..09d74070a49b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
@@ -70,7 +70,7 @@
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 = 42,
+ .dpte_buffer_size_in_pte_reqs_luma = 42,
.dpp_output_buffer_pixels = 2560,
.opp_output_buffer_lines = 1,
.pixel_chunk_size_kbytes = 8,
@@ -436,7 +436,6 @@ static const struct dcn_optc_mask tg_mask = {
};
static const struct bios_registers bios_regs = {
- NBIO_SR(BIOS_SCRATCH_0),
NBIO_SR(BIOS_SCRATCH_3),
NBIO_SR(BIOS_SCRATCH_6)
};
@@ -609,7 +608,7 @@ static struct output_pixel_processor *dcn10_opp_create(
return &opp->base;
}
-struct aux_engine *dcn10_aux_engine_create(
+struct dce_aux *dcn10_aux_engine_create(
struct dc_context *ctx,
uint32_t inst)
{
@@ -678,18 +677,18 @@ static struct mpc *dcn10_mpc_create(struct dc_context *ctx)
static struct hubbub *dcn10_hubbub_create(struct dc_context *ctx)
{
- struct hubbub *hubbub = kzalloc(sizeof(struct hubbub),
+ struct dcn10_hubbub *dcn10_hubbub = kzalloc(sizeof(struct dcn10_hubbub),
GFP_KERNEL);
- if (!hubbub)
+ if (!dcn10_hubbub)
return NULL;
- hubbub1_construct(hubbub, ctx,
+ hubbub1_construct(&dcn10_hubbub->base, ctx,
&hubbub_reg,
&hubbub_shift,
&hubbub_mask);
- return hubbub;
+ return &dcn10_hubbub->base;
}
static struct timing_generator *dcn10_timing_generator_create(
@@ -911,7 +910,7 @@ static void destruct(struct dcn10_resource_pool *pool)
for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
if (pool->base.engines[i] != NULL)
- pool->base.engines[i]->funcs->destroy_engine(&pool->base.engines[i]);
+ 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;
@@ -974,8 +973,8 @@ static void get_pixel_clock_parameters(
struct pixel_clk_params *pixel_clk_params)
{
const struct dc_stream_state *stream = pipe_ctx->stream;
- pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz;
- pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id;
+ pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
+ pixel_clk_params->encoder_object_id = stream->link->link_enc->id;
pixel_clk_params->signal_type = pipe_ctx->stream->signal;
pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1;
/* TODO: un-hardcode*/
@@ -991,9 +990,9 @@ static void get_pixel_clock_parameters(
pixel_clk_params->color_depth = COLOR_DEPTH_888;
if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
- pixel_clk_params->requested_pix_clk /= 2;
+ pixel_clk_params->requested_pix_clk_100hz /= 2;
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
- pixel_clk_params->requested_pix_clk *= 2;
+ pixel_clk_params->requested_pix_clk_100hz *= 2;
}
@@ -1131,6 +1130,56 @@ static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_st
return DC_OK;
}
+static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *context)
+{
+ int i, j;
+ bool video_down_scaled = false;
+ bool video_large = false;
+ bool desktop_large = false;
+ bool dcc_disabled = false;
+
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->stream_status[i].plane_count == 0)
+ continue;
+
+ if (context->stream_status[i].plane_count > 2)
+ return false;
+
+ for (j = 0; j < context->stream_status[i].plane_count; j++) {
+ struct dc_plane_state *plane =
+ context->stream_status[i].plane_states[j];
+
+
+ if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+
+ if (plane->src_rect.width > plane->dst_rect.width ||
+ plane->src_rect.height > plane->dst_rect.height)
+ video_down_scaled = true;
+
+ if (plane->src_rect.width >= 3840)
+ video_large = true;
+
+ } else {
+ if (plane->src_rect.width >= 3840)
+ desktop_large = true;
+ if (!plane->dcc.enable)
+ dcc_disabled = true;
+ }
+ }
+ }
+
+ /*
+ * Workaround: On DCN10 there is UMC issue that causes underflow when
+ * playing 4k video on 4k desktop with video downscaled and single channel
+ * memory
+ */
+ if (video_large && desktop_large && video_down_scaled && dcc_disabled &&
+ dc->dcn_soc->number_of_channels == 1)
+ return DC_FAIL_SURFACE_VALIDATE;
+
+ return DC_OK;
+}
+
static enum dc_status dcn10_get_default_swizzle_mode(struct dc_plane_state *plane_state)
{
enum dc_status result = DC_OK;
@@ -1159,6 +1208,7 @@ static const struct resource_funcs dcn10_res_pool_funcs = {
.validate_bandwidth = dcn_validate_bandwidth,
.acquire_idle_pipe_for_layer = dcn10_acquire_idle_pipe_for_layer,
.validate_plane = dcn10_validate_plane,
+ .validate_global = dcn10_validate_global,
.add_stream_to_ctx = dcn10_add_stream_to_ctx,
.get_default_swizzle_mode = dcn10_get_default_swizzle_mode
};
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 b8b5525a389a..b08254121251 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
@@ -261,17 +261,29 @@ void enc1_stream_encoder_dp_set_stream_attribute(
uint8_t dp_component_depth = 0;
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+ struct dc_crtc_timing hw_crtc_timing = *crtc_timing;
+
+ if (hw_crtc_timing.flags.INTERLACE) {
+ /*the input timing is in VESA spec format with Interlace flag =1*/
+ hw_crtc_timing.v_total /= 2;
+ hw_crtc_timing.v_border_top /= 2;
+ hw_crtc_timing.v_addressable /= 2;
+ hw_crtc_timing.v_border_bottom /= 2;
+ hw_crtc_timing.v_front_porch /= 2;
+ hw_crtc_timing.v_sync_width /= 2;
+ }
+
/* set pixel encoding */
- switch (crtc_timing->pixel_encoding) {
+ switch (hw_crtc_timing.pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR422;
break;
case PIXEL_ENCODING_YCBCR444:
dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR444;
- if (crtc_timing->flags.Y_ONLY)
- if (crtc_timing->display_color_depth != COLOR_DEPTH_666)
+ if (hw_crtc_timing.flags.Y_ONLY)
+ if (hw_crtc_timing.display_color_depth != COLOR_DEPTH_666)
/* HW testing only, no use case yet.
* Color depth of Y-only could be
* 8, 10, 12, 16 bits
@@ -299,7 +311,7 @@ void enc1_stream_encoder_dp_set_stream_attribute(
* Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7,
* and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care").
*/
- if ((crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
+ if ((hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
(output_color_space == COLOR_SPACE_2020_YCBCR) ||
(output_color_space == COLOR_SPACE_2020_RGB_FULLRANGE) ||
(output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE))
@@ -308,7 +320,7 @@ void enc1_stream_encoder_dp_set_stream_attribute(
misc1 = misc1 & ~0x40;
/* set color depth */
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_6BPC;
break;
@@ -336,7 +348,7 @@ void enc1_stream_encoder_dp_set_stream_attribute(
/* set dynamic range and YCbCr range */
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
colorimetry_bpc = 0;
break;
@@ -372,9 +384,9 @@ void enc1_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 0; /*bt601*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_YCBCR709:
@@ -382,9 +394,9 @@ void enc1_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 1; /*bt709*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
@@ -414,26 +426,26 @@ void enc1_stream_encoder_dp_set_stream_attribute(
* dc_crtc_timing is vesa dmt struct. data from edid
*/
REG_SET_2(DP_MSA_TIMING_PARAM1, 0,
- DP_MSA_HTOTAL, crtc_timing->h_total,
- DP_MSA_VTOTAL, crtc_timing->v_total);
+ DP_MSA_HTOTAL, hw_crtc_timing.h_total,
+ DP_MSA_VTOTAL, hw_crtc_timing.v_total);
/* calculate from vesa timing parameters
* h_active_start related to leading edge of sync
*/
- h_blank = crtc_timing->h_total - crtc_timing->h_border_left -
- crtc_timing->h_addressable - crtc_timing->h_border_right;
+ h_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left -
+ hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right;
- h_back_porch = h_blank - crtc_timing->h_front_porch -
- crtc_timing->h_sync_width;
+ h_back_porch = h_blank - hw_crtc_timing.h_front_porch -
+ hw_crtc_timing.h_sync_width;
/* start at beginning of left border */
- h_active_start = crtc_timing->h_sync_width + h_back_porch;
+ h_active_start = hw_crtc_timing.h_sync_width + h_back_porch;
- v_active_start = crtc_timing->v_total - crtc_timing->v_border_top -
- crtc_timing->v_addressable - crtc_timing->v_border_bottom -
- crtc_timing->v_front_porch;
+ v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top -
+ hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom -
+ hw_crtc_timing.v_front_porch;
/* start at beginning of left border */
@@ -443,20 +455,20 @@ void enc1_stream_encoder_dp_set_stream_attribute(
REG_SET_4(DP_MSA_TIMING_PARAM3, 0,
DP_MSA_HSYNCWIDTH,
- crtc_timing->h_sync_width,
+ hw_crtc_timing.h_sync_width,
DP_MSA_HSYNCPOLARITY,
- !crtc_timing->flags.HSYNC_POSITIVE_POLARITY,
+ !hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY,
DP_MSA_VSYNCWIDTH,
- crtc_timing->v_sync_width,
+ hw_crtc_timing.v_sync_width,
DP_MSA_VSYNCPOLARITY,
- !crtc_timing->flags.VSYNC_POSITIVE_POLARITY);
+ !hw_crtc_timing.flags.VSYNC_POSITIVE_POLARITY);
/* HWDITH include border or overscan */
REG_SET_2(DP_MSA_TIMING_PARAM4, 0,
- DP_MSA_HWIDTH, crtc_timing->h_border_left +
- crtc_timing->h_addressable + crtc_timing->h_border_right,
- DP_MSA_VHEIGHT, crtc_timing->v_border_top +
- crtc_timing->v_addressable + crtc_timing->v_border_bottom);
+ DP_MSA_HWIDTH, hw_crtc_timing.h_border_left +
+ 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);
}
static void enc1_stream_encoder_set_stream_attribute_helper(
@@ -594,7 +606,7 @@ void enc1_stream_encoder_dvi_set_stream_attribute(
cntl.signal = is_dual_link ?
SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK;
cntl.enable_dp_audio = false;
- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+ cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
if (enc1->base.bp->funcs->encoder_control(
@@ -1413,6 +1425,14 @@ void enc1_setup_stereo_sync(
REG_UPDATE(DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, !enable);
}
+void enc1_dig_connect_to_otg(
+ struct stream_encoder *enc,
+ int tg_inst)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+ REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
+}
static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
.dp_set_stream_attribute =
@@ -1445,6 +1465,7 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
.hdmi_audio_disable = enc1_se_hdmi_audio_disable,
.setup_stereo_sync = enc1_setup_stereo_sync,
.set_avmute = enc1_stream_encoder_set_avmute,
+ .dig_connect_to_otg = enc1_dig_connect_to_otg,
};
void dcn10_stream_encoder_construct(
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 67f3e4dd95c1..b7c800e10a32 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
@@ -274,7 +274,8 @@ struct dcn10_stream_enc_registers {
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_HWIDTH, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_VHEIGHT, mask_sh),\
SE_SF(DIG0_HDMI_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
- SE_SF(DP0_DP_VID_TIMING, DP_VID_N_MUL, mask_sh)
+ SE_SF(DP0_DP_VID_TIMING, DP_VID_N_MUL, mask_sh),\
+ SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh)
#define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\
SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh)
@@ -426,7 +427,8 @@ struct dcn10_stream_enc_registers {
type DP_MSA_VHEIGHT;\
type HDMI_DB_DISABLE;\
type DP_VID_N_MUL;\
- type DP_VID_M_DOUBLE_VALUE_EN
+ type DP_VID_M_DOUBLE_VALUE_EN;\
+ type DIG_SOURCE_SELECT
struct dcn10_stream_encoder_shift {
SE_REG_FIELD_LIST_DCN1_0(uint8_t);
@@ -523,4 +525,8 @@ void enc1_se_hdmi_audio_setup(
void enc1_se_hdmi_audio_disable(
struct stream_encoder *enc);
+void enc1_dig_connect_to_otg(
+ struct stream_encoder *enc,
+ int tg_inst);
+
#endif /* __DC_STREAM_ENCODER_DCN10_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 5d4527d03045..e81b24374bcb 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -58,6 +58,13 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
bool enable);
/*
+ * poll pending down reply before clear payload allocation table
+ */
+void dm_helpers_dp_mst_poll_pending_down_reply(
+ struct dc_context *ctx,
+ const struct dc_link *link);
+
+/*
* Clear payload allocation table before enable MST DP link.
*/
void dm_helpers_dp_mst_clear_payload_allocation_table(
diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
index 0029a39efb1c..14bed5b1fa97 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
@@ -38,7 +38,8 @@ enum pp_smu_ver {
* of interface sharing between families of ASIcs.
*/
PP_SMU_UNSUPPORTED,
- PP_SMU_VER_RV
+ PP_SMU_VER_RV,
+ PP_SMU_VER_MAX
};
struct pp_smu {
diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h
index 1af8c777b3ac..77200711abbe 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h
@@ -82,9 +82,17 @@ enum dm_pp_clock_type {
#define DC_DECODE_PP_CLOCK_TYPE(clk_type) \
(clk_type) == DM_PP_CLOCK_TYPE_DISPLAY_CLK ? "Display" : \
(clk_type) == DM_PP_CLOCK_TYPE_ENGINE_CLK ? "Engine" : \
- (clk_type) == DM_PP_CLOCK_TYPE_MEMORY_CLK ? "Memory" : "Invalid"
-
-#define DM_PP_MAX_CLOCK_LEVELS 8
+ (clk_type) == DM_PP_CLOCK_TYPE_MEMORY_CLK ? "Memory" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_DCFCLK ? "DCF" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_DCEFCLK ? "DCEF" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_SOCCLK ? "SoC" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_PIXELCLK ? "Pixel" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_DISPLAYPHYCLK ? "Display PHY" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_DPPCLK ? "DPP" : \
+ (clk_type) == DM_PP_CLOCK_TYPE_FCLK ? "F" : \
+ "Invalid"
+
+#define DM_PP_MAX_CLOCK_LEVELS 16
struct dm_pp_clock_levels {
uint32_t num_levels;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
index bea4e61b94c7..c59e582c1f40 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
@@ -121,4 +121,30 @@ enum self_refresh_affinity {
dm_neither_self_refresh_nor_mclk_switch
};
+enum dm_validation_status {
+ DML_VALIDATION_OK,
+ DML_FAIL_SCALE_RATIO_TAP,
+ DML_FAIL_SOURCE_PIXEL_FORMAT,
+ DML_FAIL_VIEWPORT_SIZE,
+ DML_FAIL_TOTAL_V_ACTIVE_BW,
+ DML_FAIL_DIO_SUPPORT,
+ DML_FAIL_NOT_ENOUGH_DSC,
+ DML_FAIL_DSC_CLK_REQUIRED,
+ DML_FAIL_URGENT_LATENCY,
+ DML_FAIL_REORDERING_BUFFER,
+ DML_FAIL_DISPCLK_DPPCLK,
+ DML_FAIL_TOTAL_AVAILABLE_PIPES,
+ DML_FAIL_NUM_OTG,
+ DML_FAIL_WRITEBACK_MODE,
+ DML_FAIL_WRITEBACK_LATENCY,
+ DML_FAIL_WRITEBACK_SCALE_RATIO_TAP,
+ DML_FAIL_CURSOR_SUPPORT,
+ DML_FAIL_PITCH_SUPPORT,
+ DML_FAIL_PTE_BUFFER_SIZE,
+ DML_FAIL_HOST_VM_IMMEDIATE_FLIP,
+ DML_FAIL_DSC_INPUT_BPC,
+ DML_FAIL_PREFETCH_SUPPORT,
+ DML_FAIL_V_RATIO_PREFETCH,
+};
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c
index dddeb0d4db8f..d303b789adfe 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c
@@ -62,3 +62,31 @@ void dml_init_instance(struct display_mode_lib *lib, enum dml_project project)
}
}
+const char *dml_get_status_message(enum dm_validation_status status)
+{
+ switch (status) {
+ case DML_VALIDATION_OK: return "Validation OK";
+ case DML_FAIL_SCALE_RATIO_TAP: return "Scale ratio/tap";
+ case DML_FAIL_SOURCE_PIXEL_FORMAT: return "Source pixel format";
+ case DML_FAIL_VIEWPORT_SIZE: return "Viewport size";
+ case DML_FAIL_TOTAL_V_ACTIVE_BW: return "Total vertical active bandwidth";
+ case DML_FAIL_DIO_SUPPORT: return "DIO support";
+ case DML_FAIL_NOT_ENOUGH_DSC: return "Not enough DSC Units";
+ case DML_FAIL_DSC_CLK_REQUIRED: return "DSC clock required";
+ case DML_FAIL_URGENT_LATENCY: return "Urgent latency";
+ case DML_FAIL_REORDERING_BUFFER: return "Re-ordering buffer";
+ case DML_FAIL_DISPCLK_DPPCLK: return "Dispclk and Dppclk";
+ case DML_FAIL_TOTAL_AVAILABLE_PIPES: return "Total available pipes";
+ case DML_FAIL_NUM_OTG: return "Number of OTG";
+ case DML_FAIL_WRITEBACK_MODE: return "Writeback mode";
+ case DML_FAIL_WRITEBACK_LATENCY: return "Writeback latency";
+ case DML_FAIL_WRITEBACK_SCALE_RATIO_TAP: return "Writeback scale ratio/tap";
+ case DML_FAIL_CURSOR_SUPPORT: return "Cursor support";
+ case DML_FAIL_PITCH_SUPPORT: return "Pitch support";
+ case DML_FAIL_PTE_BUFFER_SIZE: return "PTE buffer size";
+ case DML_FAIL_DSC_INPUT_BPC: return "DSC input bpc";
+ case DML_FAIL_PREFETCH_SUPPORT: return "Prefetch support";
+ case DML_FAIL_V_RATIO_PREFETCH: return "Vertical ratio prefetch";
+ default: return "Unknown Status";
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
index 635206248889..a730e0209c05 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
@@ -43,4 +43,6 @@ struct display_mode_lib {
void dml_init_instance(struct display_mode_lib *lib, enum dml_project project);
+const char *dml_get_status_message(enum dm_validation_status status);
+
#endif
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 5dd04520ceca..391183e3428f 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
@@ -30,22 +30,15 @@ typedef struct _vcs_dpi_soc_bounding_box_st soc_bounding_box_st;
typedef struct _vcs_dpi_ip_params_st ip_params_st;
typedef struct _vcs_dpi_display_pipe_source_params_st display_pipe_source_params_st;
typedef struct _vcs_dpi_display_output_params_st display_output_params_st;
-typedef struct _vcs_dpi_display_bandwidth_st display_bandwidth_st;
typedef struct _vcs_dpi_scaler_ratio_depth_st scaler_ratio_depth_st;
typedef struct _vcs_dpi_scaler_taps_st scaler_taps_st;
typedef struct _vcs_dpi_display_pipe_dest_params_st display_pipe_dest_params_st;
typedef struct _vcs_dpi_display_pipe_params_st display_pipe_params_st;
typedef struct _vcs_dpi_display_clocks_and_cfg_st display_clocks_and_cfg_st;
typedef struct _vcs_dpi_display_e2e_pipe_params_st display_e2e_pipe_params_st;
-typedef struct _vcs_dpi_dchub_buffer_sizing_st dchub_buffer_sizing_st;
-typedef struct _vcs_dpi_watermarks_perf_st watermarks_perf_st;
-typedef struct _vcs_dpi_cstate_pstate_watermarks_st cstate_pstate_watermarks_st;
-typedef struct _vcs_dpi_wm_calc_pipe_params_st wm_calc_pipe_params_st;
-typedef struct _vcs_dpi_vratio_pre_st vratio_pre_st;
typedef struct _vcs_dpi_display_data_rq_misc_params_st display_data_rq_misc_params_st;
typedef struct _vcs_dpi_display_data_rq_sizing_params_st display_data_rq_sizing_params_st;
typedef struct _vcs_dpi_display_data_rq_dlg_params_st display_data_rq_dlg_params_st;
-typedef struct _vcs_dpi_display_cur_rq_dlg_params_st display_cur_rq_dlg_params_st;
typedef struct _vcs_dpi_display_rq_dlg_params_st display_rq_dlg_params_st;
typedef struct _vcs_dpi_display_rq_sizing_params_st display_rq_sizing_params_st;
typedef struct _vcs_dpi_display_rq_misc_params_st display_rq_misc_params_st;
@@ -55,8 +48,6 @@ typedef struct _vcs_dpi_display_ttu_regs_st display_ttu_regs_st;
typedef struct _vcs_dpi_display_data_rq_regs_st display_data_rq_regs_st;
typedef struct _vcs_dpi_display_rq_regs_st display_rq_regs_st;
typedef struct _vcs_dpi_display_dlg_sys_params_st display_dlg_sys_params_st;
-typedef struct _vcs_dpi_display_dlg_prefetch_param_st display_dlg_prefetch_param_st;
-typedef struct _vcs_dpi_display_pipe_clock_st display_pipe_clock_st;
typedef struct _vcs_dpi_display_arb_params_st display_arb_params_st;
struct _vcs_dpi_voltage_scaling_st {
@@ -111,8 +102,6 @@ struct _vcs_dpi_soc_bounding_box_st {
double xfc_bus_transport_time_us;
double xfc_xbuf_latency_tolerance_us;
int use_urgent_burst_bw;
- double max_hscl_ratio;
- double max_vscl_ratio;
unsigned int num_states;
struct _vcs_dpi_voltage_scaling_st clock_limits[8];
};
@@ -129,7 +118,8 @@ struct _vcs_dpi_ip_params_st {
unsigned int odm_capable;
unsigned int rob_buffer_size_kbytes;
unsigned int det_buffer_size_kbytes;
- unsigned int dpte_buffer_size_in_pte_reqs;
+ 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;
unsigned int dpp_output_buffer_pixels;
unsigned int opp_output_buffer_lines;
@@ -192,7 +182,6 @@ struct _vcs_dpi_display_xfc_params_st {
struct _vcs_dpi_display_pipe_source_params_st {
int source_format;
unsigned char dcc;
- unsigned int dcc_override;
unsigned int dcc_rate;
unsigned char dcc_use_global;
unsigned char vm;
@@ -205,7 +194,6 @@ struct _vcs_dpi_display_pipe_source_params_st {
int source_scan;
int sw_mode;
int macro_tile_size;
- unsigned char is_display_sw;
unsigned int viewport_width;
unsigned int viewport_height;
unsigned int viewport_y_y;
@@ -252,16 +240,10 @@ struct _vcs_dpi_display_output_params_st {
int output_bpc;
int output_type;
int output_format;
- int output_standard;
int dsc_slices;
struct writeback_st wb;
};
-struct _vcs_dpi_display_bandwidth_st {
- double total_bw_consumed_gbps;
- double guaranteed_urgent_return_bw_gbps;
-};
-
struct _vcs_dpi_scaler_ratio_depth_st {
double hscl_ratio;
double vscl_ratio;
@@ -300,11 +282,9 @@ struct _vcs_dpi_display_pipe_dest_params_st {
unsigned int vupdate_width;
unsigned int vready_offset;
unsigned char interlaced;
- unsigned char underscan;
double pixel_rate_mhz;
unsigned char synchronized_vblank_all_planes;
unsigned char otg_inst;
- unsigned char odm_split_cnt;
unsigned char odm_combine;
unsigned char use_maximum_vstartup;
};
@@ -331,65 +311,6 @@ struct _vcs_dpi_display_e2e_pipe_params_st {
display_clocks_and_cfg_st clks_cfg;
};
-struct _vcs_dpi_dchub_buffer_sizing_st {
- unsigned int swath_width_y;
- unsigned int swath_height_y;
- unsigned int swath_height_c;
- unsigned int detail_buffer_size_y;
-};
-
-struct _vcs_dpi_watermarks_perf_st {
- double stutter_eff_in_active_region_percent;
- double urgent_latency_supported_us;
- double non_urgent_latency_supported_us;
- double dram_clock_change_margin_us;
- double dram_access_eff_percent;
-};
-
-struct _vcs_dpi_cstate_pstate_watermarks_st {
- double cstate_exit_us;
- double cstate_enter_plus_exit_us;
- double pstate_change_us;
-};
-
-struct _vcs_dpi_wm_calc_pipe_params_st {
- unsigned int num_dpp;
- int voltage;
- int output_type;
- double dcfclk_mhz;
- double socclk_mhz;
- double dppclk_mhz;
- double pixclk_mhz;
- unsigned char interlace_en;
- unsigned char pte_enable;
- unsigned char dcc_enable;
- double dcc_rate;
- double bytes_per_pixel_c;
- double bytes_per_pixel_y;
- unsigned int swath_width_y;
- unsigned int swath_height_y;
- unsigned int swath_height_c;
- unsigned int det_buffer_size_y;
- double h_ratio;
- double v_ratio;
- unsigned int h_taps;
- unsigned int h_total;
- unsigned int v_total;
- unsigned int v_active;
- unsigned int e2e_index;
- double display_pipe_line_delivery_time;
- double read_bw;
- unsigned int lines_in_det_y;
- unsigned int lines_in_det_y_rounded_down_to_swath;
- double full_det_buffering_time;
- double dcfclk_deepsleep_mhz_per_plane;
-};
-
-struct _vcs_dpi_vratio_pre_st {
- double vratio_pre_l;
- double vratio_pre_c;
-};
-
struct _vcs_dpi_display_data_rq_misc_params_st {
unsigned int full_swath_bytes;
unsigned int stored_swath_bytes;
@@ -423,16 +344,9 @@ struct _vcs_dpi_display_data_rq_dlg_params_st {
unsigned int meta_bytes_per_row_ub;
};
-struct _vcs_dpi_display_cur_rq_dlg_params_st {
- unsigned char enable;
- unsigned int swath_height;
- unsigned int req_per_line;
-};
-
struct _vcs_dpi_display_rq_dlg_params_st {
display_data_rq_dlg_params_st rq_l;
display_data_rq_dlg_params_st rq_c;
- display_cur_rq_dlg_params_st rq_cur0;
};
struct _vcs_dpi_display_rq_sizing_params_st {
@@ -498,6 +412,10 @@ struct _vcs_dpi_display_dlg_regs_st {
unsigned int xfc_reg_remote_surface_flip_latency;
unsigned int xfc_reg_prefetch_margin;
unsigned int dst_y_delta_drq_limit;
+ unsigned int refcyc_per_vm_group_vblank;
+ unsigned int refcyc_per_vm_group_flip;
+ unsigned int refcyc_per_vm_req_vblank;
+ unsigned int refcyc_per_vm_req_flip;
};
struct _vcs_dpi_display_ttu_regs_st {
@@ -556,19 +474,6 @@ struct _vcs_dpi_display_dlg_sys_params_st {
unsigned int total_flip_bytes;
};
-struct _vcs_dpi_display_dlg_prefetch_param_st {
- double prefetch_bw;
- unsigned int flip_bytes;
-};
-
-struct _vcs_dpi_display_pipe_clock_st {
- double dcfclk_mhz;
- double dispclk_mhz;
- double socclk_mhz;
- double dscclk_mhz[6];
- double dppclk_mhz[6];
-};
-
struct _vcs_dpi_display_arb_params_st {
int max_req_outstanding;
int min_req_outstanding;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c
index c2037daa8e66..ad8571f5a142 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c
@@ -459,7 +459,7 @@ static void dml1_rq_dlg_get_row_heights(
/* dpte */
/* ------ */
log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes);
- dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs;
+ dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma;
log2_vmpg_height = 0;
log2_vmpg_width = 0;
@@ -776,7 +776,7 @@ static void get_surf_rq_param(
/* dpte */
/* ------ */
log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes);
- dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs;
+ dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma;
log2_vmpg_height = 0;
log2_vmpg_width = 0;
@@ -881,7 +881,7 @@ static void get_surf_rq_param(
/* the dpte_group_bytes is reduced for the specific case of vertical
* access of a tile surface that has dpte request of 8x1 ptes.
*/
- if (!surf_linear & (log2_dpte_req_height_ptes == 0) & surf_vert) /*reduced, in this case, will have page fault within a group */
+ if (!surf_linear && (log2_dpte_req_height_ptes == 0) && surf_vert) /*reduced, in this case, will have page fault within a group */
rq_sizing_param->dpte_group_bytes = 512;
else
/*full size */
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
index 1d1efd72b291..cf76ea2d9f5a 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
@@ -101,6 +101,18 @@ enum gpio_mode dal_gpio_get_mode(
return gpio->mode;
}
+enum gpio_result dal_gpio_lock_pin(
+ struct gpio *gpio)
+{
+ return dal_gpio_service_lock(gpio->service, gpio->id, gpio->en);
+}
+
+enum gpio_result dal_gpio_unlock_pin(
+ struct gpio *gpio)
+{
+ return dal_gpio_service_unlock(gpio->service, gpio->id, gpio->en);
+}
+
enum gpio_result dal_gpio_change_mode(
struct gpio *gpio,
enum gpio_mode mode)
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 dada04296025..3c63a3c04dbb 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
@@ -192,6 +192,34 @@ static void set_pin_free(
service->busyness[id][en] = false;
}
+enum gpio_result dal_gpio_service_lock(
+ struct gpio_service *service,
+ enum gpio_id id,
+ uint32_t en)
+{
+ if (!service->busyness[id]) {
+ ASSERT_CRITICAL(false);
+ return GPIO_RESULT_OPEN_FAILED;
+ }
+
+ set_pin_busy(service, id, en);
+ return GPIO_RESULT_OK;
+}
+
+enum gpio_result dal_gpio_service_unlock(
+ struct gpio_service *service,
+ enum gpio_id id,
+ uint32_t en)
+{
+ if (!service->busyness[id]) {
+ ASSERT_CRITICAL(false);
+ return GPIO_RESULT_OPEN_FAILED;
+ }
+
+ set_pin_free(service, id, en);
+ return GPIO_RESULT_OK;
+}
+
enum gpio_result dal_gpio_service_open(
struct gpio_service *service,
enum gpio_id id,
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
index 1d501a43d13b..0c678af75331 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
@@ -52,4 +52,14 @@ void dal_gpio_service_close(
struct gpio_service *service,
struct hw_gpio_pin **ptr);
+enum gpio_result dal_gpio_service_lock(
+ struct gpio_service *service,
+ enum gpio_id id,
+ uint32_t en);
+
+enum gpio_result dal_gpio_service_unlock(
+ struct gpio_service *service,
+ enum gpio_id id,
+ uint32_t en);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile
deleted file mode 100644
index 352885cb4d07..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Copyright 2017 Advanced Micro Devices, Inc.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-#
-# Makefile for the 'i2c' sub-component of DAL.
-# It provides the control and status of HW i2c engine of the adapter.
-
-I2CAUX = aux_engine.o engine_base.o i2caux.o i2c_engine.o \
- i2c_generic_hw_engine.o i2c_hw_engine.o i2c_sw_engine.o
-
-AMD_DAL_I2CAUX = $(addprefix $(AMDDALPATH)/dc/i2caux/,$(I2CAUX))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX)
-
-###############################################################################
-# DCE 8x family
-###############################################################################
-I2CAUX_DCE80 = i2caux_dce80.o i2c_hw_engine_dce80.o \
- i2c_sw_engine_dce80.o
-
-AMD_DAL_I2CAUX_DCE80 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce80/,$(I2CAUX_DCE80))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE80)
-
-###############################################################################
-# DCE 100 family
-###############################################################################
-I2CAUX_DCE100 = i2caux_dce100.o
-
-AMD_DAL_I2CAUX_DCE100 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce100/,$(I2CAUX_DCE100))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE100)
-
-###############################################################################
-# DCE 110 family
-###############################################################################
-I2CAUX_DCE110 = i2caux_dce110.o i2c_sw_engine_dce110.o i2c_hw_engine_dce110.o \
- aux_engine_dce110.o
-
-AMD_DAL_I2CAUX_DCE110 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce110/,$(I2CAUX_DCE110))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE110)
-
-###############################################################################
-# DCE 112 family
-###############################################################################
-I2CAUX_DCE112 = i2caux_dce112.o
-
-AMD_DAL_I2CAUX_DCE112 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce112/,$(I2CAUX_DCE112))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE112)
-
-###############################################################################
-# DCN 1.0 family
-###############################################################################
-ifdef CONFIG_DRM_AMD_DC_DCN1_0
-I2CAUX_DCN1 = i2caux_dcn10.o
-
-AMD_DAL_I2CAUX_DCN1 = $(addprefix $(AMDDALPATH)/dc/i2caux/dcn10/,$(I2CAUX_DCN1))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCN1)
-endif
-
-###############################################################################
-# DCE 120 family
-###############################################################################
-I2CAUX_DCE120 = i2caux_dce120.o
-
-AMD_DAL_I2CAUX_DCE120 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce120/,$(I2CAUX_DCE120))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE120)
-
-###############################################################################
-# Diagnostics on FPGA
-###############################################################################
-I2CAUX_DIAG = i2caux_diag.o
-
-AMD_DAL_I2CAUX_DIAG = $(addprefix $(AMDDALPATH)/dc/i2caux/diagnostics/,$(I2CAUX_DIAG))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DIAG)
-
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c
deleted file mode 100644
index 8cbf38b2470d..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dm_event_log.h"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "aux_engine.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-#include "include/link_service_types.h"
-
-/*
- * This unit
- */
-
-enum {
- AUX_INVALID_REPLY_RETRY_COUNTER = 1,
- AUX_TIMED_OUT_RETRY_COUNTER = 2,
- AUX_DEFER_RETRY_COUNTER = 6
-};
-
-#define FROM_ENGINE(ptr) \
- container_of((ptr), struct aux_engine, base)
-#define DC_LOGGER \
- engine->base.ctx->logger
-
-enum i2caux_engine_type dal_aux_engine_get_engine_type(
- const struct engine *engine)
-{
- return I2CAUX_ENGINE_TYPE_AUX;
-}
-
-bool dal_aux_engine_acquire(
- struct engine *engine,
- struct ddc *ddc)
-{
- struct aux_engine *aux_engine = FROM_ENGINE(engine);
-
- enum gpio_result result;
- if (aux_engine->funcs->is_engine_available) {
- /*check whether SW could use the engine*/
- if (!aux_engine->funcs->is_engine_available(aux_engine)) {
- return false;
- }
- }
-
- result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
- GPIO_DDC_CONFIG_TYPE_MODE_AUX);
-
- if (result != GPIO_RESULT_OK)
- return false;
-
- if (!aux_engine->funcs->acquire_engine(aux_engine)) {
- dal_ddc_close(ddc);
- return false;
- }
-
- engine->ddc = ddc;
-
- return true;
-}
-
-struct read_command_context {
- uint8_t *buffer;
- uint32_t current_read_length;
- uint32_t offset;
- enum i2caux_transaction_status status;
-
- struct aux_request_transaction_data request;
- struct aux_reply_transaction_data reply;
-
- uint8_t returned_byte;
-
- uint32_t timed_out_retry_aux;
- uint32_t invalid_reply_retry_aux;
- uint32_t defer_retry_aux;
- uint32_t defer_retry_i2c;
- uint32_t invalid_reply_retry_aux_on_ack;
-
- bool transaction_complete;
- bool operation_succeeded;
-};
-
-static void process_read_reply(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->defer_retry_aux = 0;
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else if (ctx->returned_byte < ctx->current_read_length) {
- ctx->current_read_length -= ctx->returned_byte;
-
- ctx->offset += ctx->returned_byte;
-
- ++ctx->invalid_reply_retry_aux_on_ack;
-
- if (ctx->invalid_reply_retry_aux_on_ack >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- }
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->transaction_complete = true;
- ctx->operation_succeeded = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-
-static void process_read_request(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
-
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else {
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->buffer;
-
- process_read_reply(engine, ctx);
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-
-static bool read_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct read_command_context ctx;
-
- ctx.buffer = request->payload.data;
- ctx.current_read_length = request->payload.length;
- ctx.offset = 0;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.invalid_reply_retry_aux_on_ack = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_READ;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- do {
- memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
-
- ctx.request.data = ctx.buffer + ctx.offset;
- ctx.request.length = ctx.current_read_length;
-
- process_read_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-
-struct write_command_context {
- bool mot;
-
- uint8_t *buffer;
- uint32_t current_write_length;
- enum i2caux_transaction_status status;
-
- struct aux_request_transaction_data request;
- struct aux_reply_transaction_data reply;
-
- uint8_t returned_byte;
-
- uint32_t timed_out_retry_aux;
- uint32_t invalid_reply_retry_aux;
- uint32_t defer_retry_aux;
- uint32_t defer_retry_i2c;
- uint32_t max_defer_retry;
- uint32_t ack_m_retry;
-
- uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
-
- bool transaction_complete;
- bool operation_succeeded;
-};
-
-static void process_write_reply(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->operation_succeeded = true;
-
- if (ctx->returned_byte) {
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ctx->current_write_length = 0;
-
- ++ctx->ack_m_retry;
-
- if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else
- udelay(300);
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->defer_retry_aux = 0;
- ctx->ack_m_retry = 0;
- ctx->transaction_complete = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
- ctx->current_write_length = 0;
-
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-
-static void process_write_request(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
-
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->reply_data;
-
- process_write_reply(engine, ctx);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-
-static bool write_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct write_command_context ctx;
-
- ctx.mot = middle_of_transaction;
- ctx.buffer = request->payload.data;
- ctx.current_write_length = request->payload.length;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.ack_m_retry = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- ctx.max_defer_retry =
- (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
- engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
-
- do {
- ctx.request.data = ctx.buffer;
- ctx.request.length = ctx.current_write_length;
-
- process_write_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-
-static bool end_of_transaction_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request)
-{
- struct i2caux_transaction_request dummy_request;
- uint8_t dummy_data;
-
- /* [tcheng] We only need to send the stop (read with MOT = 0)
- * for I2C-over-Aux, not native AUX */
-
- if (request->payload.address_space !=
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
- return false;
-
- dummy_request.operation = request->operation;
- dummy_request.payload.address_space = request->payload.address_space;
- dummy_request.payload.address = request->payload.address;
-
- /*
- * Add a dummy byte due to some receiver quirk
- * where one byte is sent along with MOT = 0.
- * Ideally this should be 0.
- */
-
- dummy_request.payload.length = 0;
- dummy_request.payload.data = &dummy_data;
-
- if (request->operation == I2CAUX_TRANSACTION_READ)
- return read_command(engine, &dummy_request, false);
- else
- return write_command(engine, &dummy_request, false);
-
- /* according Syed, it does not need now DoDummyMOT */
-}
-
-bool dal_aux_engine_submit_request(
- struct engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct aux_engine *aux_engine = FROM_ENGINE(engine);
-
- bool result;
- bool mot_used = true;
-
- switch (request->operation) {
- case I2CAUX_TRANSACTION_READ:
- result = read_command(aux_engine, request, mot_used);
- break;
- case I2CAUX_TRANSACTION_WRITE:
- result = write_command(aux_engine, request, mot_used);
- break;
- default:
- result = false;
- }
-
- /* [tcheng]
- * need to send stop for the last transaction to free up the AUX
- * if the above command fails, this would be the last transaction */
-
- if (!middle_of_transaction || !result)
- end_of_transaction_command(aux_engine, request);
-
- /* mask AUX interrupt */
-
- return result;
-}
-
-void dal_aux_engine_construct(
- struct aux_engine *engine,
- struct dc_context *ctx)
-{
- dal_i2caux_construct_engine(&engine->base, ctx);
- engine->delay = 0;
- engine->max_defer_write_retry = 0;
-}
-
-void dal_aux_engine_destruct(
- struct aux_engine *engine)
-{
- dal_i2caux_destruct_engine(&engine->base);
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h
deleted file mode 100644
index c33a2898d967..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_AUX_ENGINE_H__
-#define __DAL_AUX_ENGINE_H__
-
-#include "dc_ddc_types.h"
-
-struct aux_engine;
-
-struct aux_engine_funcs {
- void (*destroy)(
- struct aux_engine **ptr);
- bool (*acquire_engine)(
- struct aux_engine *engine);
- void (*configure)(
- struct aux_engine *engine,
- union aux_config cfg);
- void (*submit_channel_request)(
- struct aux_engine *engine,
- struct aux_request_transaction_data *request);
- void (*process_channel_reply)(
- struct aux_engine *engine,
- struct aux_reply_transaction_data *reply);
- int (*read_channel_reply)(
- struct aux_engine *engine,
- uint32_t size,
- uint8_t *buffer,
- uint8_t *reply_result,
- uint32_t *sw_status);
- enum aux_channel_operation_result (*get_channel_status)(
- struct aux_engine *engine,
- uint8_t *returned_bytes);
- bool (*is_engine_available) (
- struct aux_engine *engine);
-};
-
-struct aux_engine {
- struct engine base;
- const struct aux_engine_funcs *funcs;
- /* following values are expressed in milliseconds */
- uint32_t delay;
- uint32_t max_defer_write_retry;
-
- bool acquire_reset;
-};
-
-void dal_aux_engine_construct(
- struct aux_engine *engine,
- struct dc_context *ctx);
-
-void dal_aux_engine_destruct(
- struct aux_engine *engine);
-bool dal_aux_engine_submit_request(
- struct engine *ptr,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction);
-bool dal_aux_engine_acquire(
- struct engine *ptr,
- struct ddc *ddc);
-enum i2caux_engine_type dal_aux_engine_get_engine_type(
- const struct engine *engine);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c
deleted file mode 100644
index 8b704ab0471c..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-#include "../dce110/aux_engine_dce110.h"
-#include "../dce110/i2c_hw_engine_dce110.h"
-#include "../dce110/i2caux_dce110.h"
-
-#include "dce/dce_10_0_d.h"
-#include "dce/dce_10_0_sh_mask.h"
-
-/* set register offset */
-#define SR(reg_name)\
- .reg_name = mm ## reg_name
-
-/* set register offset with instance */
-#define SRI(reg_name, block, id)\
- .reg_name = mm ## block ## id ## _ ## reg_name
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = 0 \
-}
-
-#define hw_engine_regs(id)\
-{\
- I2C_HW_ENGINE_COMMON_REG_LIST(id) \
-}
-
-static const struct dce110_aux_registers dce100_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5),
-};
-
-static const struct dce110_i2c_hw_engine_registers dce100_hw_engine_regs[] = {
- hw_engine_regs(1),
- hw_engine_regs(2),
- hw_engine_regs(3),
- hw_engine_regs(4),
- hw_engine_regs(5),
- hw_engine_regs(6)
-};
-
-static const struct dce110_i2c_hw_engine_shift i2c_shift = {
- I2C_COMMON_MASK_SH_LIST_DCE100(__SHIFT)
-};
-
-static const struct dce110_i2c_hw_engine_mask i2c_mask = {
- I2C_COMMON_MASK_SH_LIST_DCE100(_MASK)
-};
-
-struct i2caux *dal_i2caux_dce100_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce110 *i2caux_dce110 =
- kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL);
-
- if (!i2caux_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- dal_i2caux_dce110_construct(i2caux_dce110,
- ctx,
- ARRAY_SIZE(dce100_aux_regs),
- dce100_aux_regs,
- dce100_hw_engine_regs,
- &i2c_shift,
- &i2c_mask);
- return &i2caux_dce110->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c
deleted file mode 100644
index 59c3ed43d609..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dm_event_log.h"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../engine.h"
-#include "../aux_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "aux_engine_dce110.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-#include "dce/dce_11_0_sh_mask.h"
-
-#define CTX \
- aux110->base.base.ctx
-#define REG(reg_name)\
- (aux110->regs->reg_name)
-#include "reg_helper.h"
-
-/*
- * This unit
- */
-
-/*
- * @brief
- * Cast 'struct aux_engine *'
- * to 'struct aux_engine_dce110 *'
- */
-#define FROM_AUX_ENGINE(ptr) \
- container_of((ptr), struct aux_engine_dce110, base)
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct aux_engine_dce110 *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
-
-static void release_engine(
- struct engine *engine)
-{
- struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine);
-
- REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
-}
-
-static void destruct(
- struct aux_engine_dce110 *engine);
-
-static void destroy(
- struct aux_engine **aux_engine)
-{
- struct aux_engine_dce110 *engine = FROM_AUX_ENGINE(*aux_engine);
-
- destruct(engine);
-
- kfree(engine);
-
- *aux_engine = NULL;
-}
-
-#define SW_CAN_ACCESS_AUX 1
-#define DMCU_CAN_ACCESS_AUX 2
-
-static bool is_engine_available(
- struct aux_engine *engine)
-{
- struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
-
- uint32_t value = REG_READ(AUX_ARB_CONTROL);
- uint32_t field = get_reg_field_value(
- value,
- AUX_ARB_CONTROL,
- AUX_REG_RW_CNTL_STATUS);
-
- return (field != DMCU_CAN_ACCESS_AUX);
-}
-static bool acquire_engine(
- struct aux_engine *engine)
-{
- struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
-
- uint32_t value = REG_READ(AUX_ARB_CONTROL);
- uint32_t field = get_reg_field_value(
- value,
- AUX_ARB_CONTROL,
- AUX_REG_RW_CNTL_STATUS);
- if (field == DMCU_CAN_ACCESS_AUX)
- return false;
- /* enable AUX before request SW to access AUX */
- value = REG_READ(AUX_CONTROL);
- field = get_reg_field_value(value,
- AUX_CONTROL,
- AUX_EN);
-
- if (field == 0) {
- set_reg_field_value(
- value,
- 1,
- AUX_CONTROL,
- AUX_EN);
-
- if (REG(AUX_RESET_MASK)) {
- /*DP_AUX block as part of the enable sequence*/
- set_reg_field_value(
- value,
- 1,
- AUX_CONTROL,
- AUX_RESET);
- }
-
- REG_WRITE(AUX_CONTROL, value);
-
- if (REG(AUX_RESET_MASK)) {
- /*poll HW to make sure reset it done*/
-
- REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
- 1, 11);
-
- set_reg_field_value(
- value,
- 0,
- AUX_CONTROL,
- AUX_RESET);
-
- REG_WRITE(AUX_CONTROL, value);
-
- REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
- 1, 11);
- }
- } /*if (field)*/
-
- /* request SW to access AUX */
- REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
-
- value = REG_READ(AUX_ARB_CONTROL);
- field = get_reg_field_value(
- value,
- AUX_ARB_CONTROL,
- AUX_REG_RW_CNTL_STATUS);
-
- return (field == SW_CAN_ACCESS_AUX);
-}
-
-#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
- ((command) | ((0xF0000 & (address)) >> 16))
-
-#define COMPOSE_AUX_SW_DATA_8_15(address) \
- ((0xFF00 & (address)) >> 8)
-
-#define COMPOSE_AUX_SW_DATA_0_7(address) \
- (0xFF & (address))
-
-static void submit_channel_request(
- struct aux_engine *engine,
- struct aux_request_transaction_data *request)
-{
- struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
- uint32_t value;
- uint32_t length;
-
- bool is_write =
- ((request->type == AUX_TRANSACTION_TYPE_DP) &&
- (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
- ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
- ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
- (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
- if (REG(AUXN_IMPCAL)) {
- /* clear_aux_error */
- REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
- 1,
- 0);
-
- REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
- 1,
- 0);
-
- /* force_default_calibrate */
- REG_UPDATE_1BY1_2(AUXN_IMPCAL,
- AUXN_IMPCAL_ENABLE, 1,
- AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
-
- /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
-
- REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
- 1,
- 0);
- }
- /* set the delay and the number of bytes to write */
-
- /* The length include
- * the 4 bit header and the 20 bit address
- * (that is 3 byte).
- * If the requested length is non zero this means
- * an addition byte specifying the length is required. */
-
- length = request->length ? 4 : 3;
- if (is_write)
- length += request->length;
-
- REG_UPDATE_2(AUX_SW_CONTROL,
- AUX_SW_START_DELAY, request->delay,
- AUX_SW_WR_BYTES, length);
-
- /* program action and address and payload data (if 'is_write') */
- value = REG_UPDATE_4(AUX_SW_DATA,
- AUX_SW_INDEX, 0,
- AUX_SW_DATA_RW, 0,
- AUX_SW_AUTOINCREMENT_DISABLE, 1,
- AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
-
- value = REG_SET_2(AUX_SW_DATA, value,
- AUX_SW_AUTOINCREMENT_DISABLE, 0,
- AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
-
- value = REG_SET(AUX_SW_DATA, value,
- AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
-
- if (request->length) {
- value = REG_SET(AUX_SW_DATA, value,
- AUX_SW_DATA, request->length - 1);
- }
-
- if (is_write) {
- /* Load the HW buffer with the Data to be sent.
- * This is relevant for write operation.
- * For read, the data recived data will be
- * processed in process_channel_reply(). */
- uint32_t i = 0;
-
- while (i < request->length) {
- value = REG_SET(AUX_SW_DATA, value,
- AUX_SW_DATA, request->data[i]);
-
- ++i;
- }
- }
-
- REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
- REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
- 10, aux110->timeout_period/10);
- REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
- EVENT_LOG_AUX_REQ(engine->base.ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
- request->action, request->address, request->length, request->data);
-}
-
-static int read_channel_reply(struct aux_engine *engine, uint32_t size,
- uint8_t *buffer, uint8_t *reply_result,
- uint32_t *sw_status)
-{
- struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
- uint32_t bytes_replied;
- uint32_t reply_result_32;
-
- *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
- &bytes_replied);
-
- /* In case HPD is LOW, exit AUX transaction */
- if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
- return -1;
-
- /* Need at least the status byte */
- if (!bytes_replied)
- return -1;
-
- REG_UPDATE_1BY1_3(AUX_SW_DATA,
- AUX_SW_INDEX, 0,
- AUX_SW_AUTOINCREMENT_DISABLE, 1,
- AUX_SW_DATA_RW, 1);
-
- REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
- reply_result_32 = reply_result_32 >> 4;
- *reply_result = (uint8_t)reply_result_32;
-
- if (reply_result_32 == 0) { /* ACK */
- uint32_t i = 0;
-
- /* First byte was already used to get the command status */
- --bytes_replied;
-
- /* Do not overflow buffer */
- if (bytes_replied > size)
- return -1;
-
- while (i < bytes_replied) {
- uint32_t aux_sw_data_val;
-
- REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
- buffer[i] = aux_sw_data_val;
- ++i;
- }
-
- return i;
- }
-
- return 0;
-}
-
-static void process_channel_reply(
- struct aux_engine *engine,
- struct aux_reply_transaction_data *reply)
-{
- int bytes_replied;
- uint8_t reply_result;
- uint32_t sw_status;
-
- bytes_replied = read_channel_reply(engine, reply->length, reply->data,
- &reply_result, &sw_status);
- EVENT_LOG_AUX_REP(engine->base.ddc->pin_data->en,
- EVENT_LOG_AUX_ORIGIN_NATIVE, reply_result,
- bytes_replied, reply->data);
-
- /* in case HPD is LOW, exit AUX transaction */
- if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
- return;
- }
-
- if (bytes_replied < 0) {
- /* Need to handle an error case...
- * Hopefully, upper layer function won't call this function if
- * the number of bytes in the reply was 0, because there was
- * surely an error that was asserted that should have been
- * handled for hot plug case, this could happens
- */
- if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- ASSERT_CRITICAL(false);
- return;
- }
- } else {
-
- switch (reply_result) {
- case 0: /* ACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
- break;
- case 1: /* NACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
- break;
- case 2: /* DEFER */
- reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
- break;
- case 4: /* AUX ACK / I2C NACK */
- reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
- break;
- case 8: /* AUX ACK / I2C DEFER */
- reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
- break;
- default:
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- }
- }
-}
-
-static enum aux_channel_operation_result get_channel_status(
- struct aux_engine *engine,
- uint8_t *returned_bytes)
-{
- struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
-
- uint32_t value;
-
- if (returned_bytes == NULL) {
- /*caller pass NULL pointer*/
- ASSERT_CRITICAL(false);
- return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
- }
- *returned_bytes = 0;
-
- /* poll to make sure that SW_DONE is asserted */
- value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
- 10, aux110->timeout_period/10);
-
- /* in case HPD is LOW, exit AUX transaction */
- if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
- return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
-
- /* Note that the following bits are set in 'status.bits'
- * during CTS 4.2.1.2 (FW 3.3.1):
- * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
- * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
- *
- * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
- * HW debugging bit and should be ignored. */
- if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
- if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
- (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
- return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
-
- else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
- (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
- (value &
- AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
- (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
- return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
-
- *returned_bytes = get_reg_field_value(value,
- AUX_SW_STATUS,
- AUX_SW_REPLY_BYTE_COUNT);
-
- if (*returned_bytes == 0)
- return
- AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
- else {
- *returned_bytes -= 1;
- return AUX_CHANNEL_OPERATION_SUCCEEDED;
- }
- } else {
- /*time_elapsed >= aux_engine->timeout_period
- * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
- */
- ASSERT_CRITICAL(false);
- return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
- }
-}
-
-static const struct aux_engine_funcs aux_engine_funcs = {
- .destroy = destroy,
- .acquire_engine = acquire_engine,
- .submit_channel_request = submit_channel_request,
- .process_channel_reply = process_channel_reply,
- .read_channel_reply = read_channel_reply,
- .get_channel_status = get_channel_status,
- .is_engine_available = is_engine_available,
-};
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .submit_request = dal_aux_engine_submit_request,
- .get_engine_type = dal_aux_engine_get_engine_type,
- .acquire = dal_aux_engine_acquire,
-};
-
-static void construct(
- struct aux_engine_dce110 *engine,
- const struct aux_engine_dce110_init_data *aux_init_data)
-{
- dal_aux_engine_construct(&engine->base, aux_init_data->ctx);
- engine->base.base.funcs = &engine_funcs;
- engine->base.funcs = &aux_engine_funcs;
-
- engine->timeout_period = aux_init_data->timeout_period;
- engine->regs = aux_init_data->regs;
-}
-
-static void destruct(
- struct aux_engine_dce110 *engine)
-{
- dal_aux_engine_destruct(&engine->base);
-}
-
-struct aux_engine *dal_aux_engine_dce110_create(
- const struct aux_engine_dce110_init_data *aux_init_data)
-{
- struct aux_engine_dce110 *engine;
-
- if (!aux_init_data) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- engine = kzalloc(sizeof(*engine), GFP_KERNEL);
-
- if (!engine) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- construct(engine, aux_init_data);
- return &engine->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h
deleted file mode 100644
index 85ee82162590..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_AUX_ENGINE_DCE110_H__
-#define __DAL_AUX_ENGINE_DCE110_H__
-
-#include "../aux_engine.h"
-
-#define AUX_COMMON_REG_LIST(id)\
- SRI(AUX_CONTROL, DP_AUX, id), \
- SRI(AUX_ARB_CONTROL, DP_AUX, id), \
- SRI(AUX_SW_DATA, DP_AUX, id), \
- SRI(AUX_SW_CONTROL, DP_AUX, id), \
- SRI(AUX_INTERRUPT_CONTROL, DP_AUX, id), \
- SRI(AUX_SW_STATUS, DP_AUX, id), \
- SR(AUXN_IMPCAL), \
- SR(AUXP_IMPCAL)
-
-struct dce110_aux_registers {
- uint32_t AUX_CONTROL;
- uint32_t AUX_ARB_CONTROL;
- uint32_t AUX_SW_DATA;
- uint32_t AUX_SW_CONTROL;
- uint32_t AUX_INTERRUPT_CONTROL;
- uint32_t AUX_SW_STATUS;
- uint32_t AUXN_IMPCAL;
- uint32_t AUXP_IMPCAL;
-
- uint32_t AUX_RESET_MASK;
-};
-
-struct aux_engine_dce110 {
- struct aux_engine base;
- const struct dce110_aux_registers *regs;
- struct {
- uint32_t aux_control;
- uint32_t aux_arb_control;
- uint32_t aux_sw_data;
- uint32_t aux_sw_control;
- uint32_t aux_interrupt_control;
- uint32_t aux_sw_status;
- } addr;
- uint32_t timeout_period;
-};
-
-struct aux_engine_dce110_init_data {
- uint32_t engine_id;
- uint32_t timeout_period;
- struct dc_context *ctx;
- const struct dce110_aux_registers *regs;
-};
-
-struct aux_engine *dal_aux_engine_dce110_create(
- const struct aux_engine_dce110_init_data *aux_init_data);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c
deleted file mode 100644
index 9cbe1a7a6bcb..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-/*
- * Pre-requisites: headers required by header of this unit
- */
-
-#include "include/i2caux_interface.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_hw_engine.h"
-#include "../i2c_generic_hw_engine.h"
-/*
- * Header of this unit
- */
-
-#include "i2c_hw_engine_dce110.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-#include "reg_helper.h"
-
-/*
- * This unit
- */
-#define DC_LOGGER \
- hw_engine->base.base.base.ctx->logger
-
-enum dc_i2c_status {
- DC_I2C_STATUS__DC_I2C_STATUS_IDLE,
- DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW,
- DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW
-};
-
-enum dc_i2c_arbitration {
- DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL,
- DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH
-};
-
-
-
-/*
- * @brief
- * Cast pointer to 'struct i2c_hw_engine *'
- * to pointer 'struct i2c_hw_engine_dce110 *'
- */
-#define FROM_I2C_HW_ENGINE(ptr) \
- container_of((ptr), struct i2c_hw_engine_dce110, base)
-/*
- * @brief
- * Cast pointer to 'struct i2c_engine *'
- * to pointer to 'struct i2c_hw_engine_dce110 *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base))
-
-/*
- * @brief
- * Cast pointer to 'struct engine *'
- * to 'pointer to struct i2c_hw_engine_dce110 *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-#define CTX \
- hw_engine->base.base.base.ctx
-
-#define REG(reg_name)\
- (hw_engine->regs->reg_name)
-
-#undef FN
-#define FN(reg_name, field_name) \
- hw_engine->i2c_shift->field_name, hw_engine->i2c_mask->field_name
-
-#include "reg_helper.h"
-
-static void disable_i2c_hw_engine(
- struct i2c_hw_engine_dce110 *hw_engine)
-{
- REG_UPDATE_N(SETUP, 1, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 0);
-}
-
-static void release_engine(
- struct engine *engine)
-{
- struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine);
-
- struct i2c_engine *base = NULL;
- bool safe_to_reset;
-
- base = &hw_engine->base.base;
-
- /* Restore original HW engine speed */
-
- base->funcs->set_speed(base, hw_engine->base.original_speed);
-
- /* Release I2C */
- REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1);
-
- /* Reset HW engine */
- {
- uint32_t i2c_sw_status = 0;
- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
- /* if used by SW, safe to reset */
- safe_to_reset = (i2c_sw_status == 1);
- }
-
- if (safe_to_reset)
- REG_UPDATE_2(
- DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET, 1,
- DC_I2C_SW_STATUS_RESET, 1);
- else
- REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1);
-
- /* HW I2c engine - clock gating feature */
- if (!hw_engine->engine_keep_power_up_count)
- disable_i2c_hw_engine(hw_engine);
-}
-
-static bool setup_engine(
- struct i2c_engine *i2c_engine)
-{
- struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine);
- uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
- uint32_t reset_length = 0;
-
- if (hw_engine->base.base.setup_limit != 0)
- i2c_setup_limit = hw_engine->base.base.setup_limit;
-
- /* Program pin select */
- REG_UPDATE_6(
- DC_I2C_CONTROL,
- DC_I2C_GO, 0,
- DC_I2C_SOFT_RESET, 0,
- DC_I2C_SEND_RESET, 0,
- DC_I2C_SW_STATUS_RESET, 1,
- DC_I2C_TRANSACTION_COUNT, 0,
- DC_I2C_DDC_SELECT, hw_engine->engine_id);
-
- /* Program time limit */
- if (hw_engine->base.base.send_reset_length == 0) {
- /*pre-dcn*/
- REG_UPDATE_N(
- SETUP, 2,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1);
- } else {
- reset_length = hw_engine->base.base.send_reset_length;
- }
- /* Program HW priority
- * set to High - interrupt software I2C at any time
- * Enable restart of SW I2C that was interrupted by HW
- * disable queuing of software while I2C is in use by HW */
- REG_UPDATE_2(
- DC_I2C_ARBITRATION,
- DC_I2C_NO_QUEUED_SW_GO, 0,
- DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
-
- return true;
-}
-
-static uint32_t get_speed(
- const struct i2c_engine *i2c_engine)
-{
- const struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine);
- uint32_t pre_scale = 0;
-
- REG_GET(SPEED, DC_I2C_DDC1_PRESCALE, &pre_scale);
-
- /* [anaumov] it seems following is unnecessary */
- /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/
- return pre_scale ?
- hw_engine->reference_frequency / pre_scale :
- hw_engine->base.default_speed;
-}
-
-static void set_speed(
- struct i2c_engine *i2c_engine,
- uint32_t speed)
-{
- struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine);
-
- if (speed) {
- if (hw_engine->i2c_mask->DC_I2C_DDC1_START_STOP_TIMING_CNTL)
- REG_UPDATE_N(
- SPEED, 3,
- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed,
- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2,
- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1);
- else
- REG_UPDATE_N(
- SPEED, 2,
- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed,
- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2);
- }
-}
-
-static inline void reset_hw_engine(struct engine *engine)
-{
- struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine);
-
- REG_UPDATE_2(
- DC_I2C_CONTROL,
- DC_I2C_SW_STATUS_RESET, 1,
- DC_I2C_SW_STATUS_RESET, 1);
-}
-
-static bool is_hw_busy(struct engine *engine)
-{
- struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine);
- uint32_t i2c_sw_status = 0;
-
- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
- return false;
-
- reset_hw_engine(engine);
-
- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
- return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
-}
-
-
-#define STOP_TRANS_PREDICAT \
- ((hw_engine->transaction_count == 3) || \
- (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || \
- (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ))
-
-#define SET_I2C_TRANSACTION(id) \
- do { \
- REG_UPDATE_N(DC_I2C_TRANSACTION##id, 5, \
- FN(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0), 1, \
- FN(DC_I2C_TRANSACTION0, DC_I2C_START0), 1, \
- FN(DC_I2C_TRANSACTION0, DC_I2C_STOP0), STOP_TRANS_PREDICAT ? 1:0, \
- FN(DC_I2C_TRANSACTION0, DC_I2C_RW0), (0 != (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)), \
- FN(DC_I2C_TRANSACTION0, DC_I2C_COUNT0), length); \
- if (STOP_TRANS_PREDICAT) \
- last_transaction = true; \
- } while (false)
-
-
-static bool process_transaction(
- struct i2c_hw_engine_dce110 *hw_engine,
- struct i2c_request_transaction_data *request)
-{
- uint32_t length = request->length;
- uint8_t *buffer = request->data;
- uint32_t value = 0;
-
- bool last_transaction = false;
-
- struct dc_context *ctx = NULL;
-
- ctx = hw_engine->base.base.base.ctx;
-
-
-
- switch (hw_engine->transaction_count) {
- case 0:
- SET_I2C_TRANSACTION(0);
- break;
- case 1:
- SET_I2C_TRANSACTION(1);
- break;
- case 2:
- SET_I2C_TRANSACTION(2);
- break;
- case 3:
- SET_I2C_TRANSACTION(3);
- break;
- default:
- /* TODO Warning ? */
- break;
- }
-
-
- /* Write the I2C address and I2C data
- * into the hardware circular buffer, one byte per entry.
- * As an example, the 7-bit I2C slave address for CRT monitor
- * for reading DDC/EDID information is 0b1010001.
- * For an I2C send operation, the LSB must be programmed to 0;
- * for I2C receive operation, the LSB must be programmed to 1. */
- if (hw_engine->transaction_count == 0) {
- value = REG_SET_4(DC_I2C_DATA, 0,
- DC_I2C_DATA_RW, false,
- DC_I2C_DATA, request->address,
- DC_I2C_INDEX, 0,
- DC_I2C_INDEX_WRITE, 1);
- hw_engine->buffer_used_write = 0;
- } else
- value = REG_SET_2(DC_I2C_DATA, 0,
- DC_I2C_DATA_RW, false,
- DC_I2C_DATA, request->address);
-
- hw_engine->buffer_used_write++;
-
- if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) {
- while (length) {
- REG_SET_2(DC_I2C_DATA, value,
- DC_I2C_INDEX_WRITE, 0,
- DC_I2C_DATA, *buffer++);
- hw_engine->buffer_used_write++;
- --length;
- }
- }
-
- ++hw_engine->transaction_count;
- hw_engine->buffer_used_bytes += length + 1;
-
- return last_transaction;
-}
-
-static void execute_transaction(
- struct i2c_hw_engine_dce110 *hw_engine)
-{
- REG_UPDATE_N(SETUP, 5,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0,
- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0);
-
-
- REG_UPDATE_5(DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET, 0,
- DC_I2C_SW_STATUS_RESET, 0,
- DC_I2C_SEND_RESET, 0,
- DC_I2C_GO, 0,
- DC_I2C_TRANSACTION_COUNT, hw_engine->transaction_count - 1);
-
- /* start I2C transfer */
- REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1);
-
- /* all transactions were executed and HW buffer became empty
- * (even though it actually happens when status becomes DONE) */
- hw_engine->transaction_count = 0;
- hw_engine->buffer_used_bytes = 0;
-}
-
-static void submit_channel_request(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *request)
-{
- request->status = I2C_CHANNEL_OPERATION_SUCCEEDED;
-
- if (!process_transaction(FROM_I2C_ENGINE(engine), request))
- return;
-
- if (is_hw_busy(&engine->base)) {
- request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
- return;
- }
-
- execute_transaction(FROM_I2C_ENGINE(engine));
-}
-
-static void process_channel_reply(
- struct i2c_engine *engine,
- struct i2c_reply_transaction_data *reply)
-{
- uint32_t length = reply->length;
- uint8_t *buffer = reply->data;
-
- struct i2c_hw_engine_dce110 *hw_engine =
- FROM_I2C_ENGINE(engine);
-
-
- REG_SET_3(DC_I2C_DATA, 0,
- DC_I2C_INDEX, hw_engine->buffer_used_write,
- DC_I2C_DATA_RW, 1,
- DC_I2C_INDEX_WRITE, 1);
-
- while (length) {
- /* after reading the status,
- * if the I2C operation executed successfully
- * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller
- * should read data bytes from I2C circular data buffer */
-
- uint32_t i2c_data;
-
- REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data);
- *buffer++ = i2c_data;
-
- --length;
- }
-}
-
-static enum i2c_channel_operation_result get_channel_status(
- struct i2c_engine *i2c_engine,
- uint8_t *returned_bytes)
-{
- uint32_t i2c_sw_status = 0;
- struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine);
- uint32_t value =
- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
-
- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW)
- return I2C_CHANNEL_OPERATION_ENGINE_BUSY;
- else if (value & hw_engine->i2c_mask->DC_I2C_SW_STOPPED_ON_NACK)
- return I2C_CHANNEL_OPERATION_NO_RESPONSE;
- else if (value & hw_engine->i2c_mask->DC_I2C_SW_TIMEOUT)
- return I2C_CHANNEL_OPERATION_TIMEOUT;
- else if (value & hw_engine->i2c_mask->DC_I2C_SW_ABORTED)
- return I2C_CHANNEL_OPERATION_FAILED;
- else if (value & hw_engine->i2c_mask->DC_I2C_SW_DONE)
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-
- /*
- * this is the case when HW used for communication, I2C_SW_STATUS
- * could be zero
- */
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-}
-
-static uint32_t get_hw_buffer_available_size(
- const struct i2c_hw_engine *engine)
-{
- return I2C_HW_BUFFER_SIZE -
- FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes;
-}
-
-static uint32_t get_transaction_timeout(
- const struct i2c_hw_engine *engine,
- uint32_t length)
-{
- uint32_t speed = engine->base.funcs->get_speed(&engine->base);
-
- uint32_t period_timeout;
- uint32_t num_of_clock_stretches;
-
- if (!speed)
- return 0;
-
- period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed;
-
- num_of_clock_stretches = 1 + (length << 3) + 1;
- num_of_clock_stretches +=
- (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) +
- (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1);
-
- return period_timeout * num_of_clock_stretches;
-}
-
-static void destroy(
- struct i2c_engine **i2c_engine)
-{
- struct i2c_hw_engine_dce110 *engine_dce110 =
- FROM_I2C_ENGINE(*i2c_engine);
-
- dal_i2c_hw_engine_destruct(&engine_dce110->base);
-
- kfree(engine_dce110);
-
- *i2c_engine = NULL;
-}
-
-static const struct i2c_engine_funcs i2c_engine_funcs = {
- .destroy = destroy,
- .get_speed = get_speed,
- .set_speed = set_speed,
- .setup_engine = setup_engine,
- .submit_channel_request = submit_channel_request,
- .process_channel_reply = process_channel_reply,
- .get_channel_status = get_channel_status,
- .acquire_engine = dal_i2c_hw_engine_acquire_engine,
-};
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .get_engine_type = dal_i2c_hw_engine_get_engine_type,
- .acquire = dal_i2c_engine_acquire,
- .submit_request = dal_i2c_hw_engine_submit_request,
-};
-
-static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = {
- .get_hw_buffer_available_size = get_hw_buffer_available_size,
- .get_transaction_timeout = get_transaction_timeout,
- .wait_on_operation_result = dal_i2c_hw_engine_wait_on_operation_result,
-};
-
-static void construct(
- struct i2c_hw_engine_dce110 *hw_engine,
- const struct i2c_hw_engine_dce110_create_arg *arg)
-{
- uint32_t xtal_ref_div = 0;
-
- dal_i2c_hw_engine_construct(&hw_engine->base, arg->ctx);
-
- hw_engine->base.base.base.funcs = &engine_funcs;
- hw_engine->base.base.funcs = &i2c_engine_funcs;
- hw_engine->base.funcs = &i2c_hw_engine_funcs;
- hw_engine->base.default_speed = arg->default_speed;
-
- hw_engine->regs = arg->regs;
- hw_engine->i2c_shift = arg->i2c_shift;
- hw_engine->i2c_mask = arg->i2c_mask;
-
- hw_engine->engine_id = arg->engine_id;
-
- hw_engine->buffer_used_bytes = 0;
- hw_engine->transaction_count = 0;
- hw_engine->engine_keep_power_up_count = 1;
-
-
- REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div);
-
- if (xtal_ref_div == 0) {
- DC_LOG_WARNING("Invalid base timer divider [%s]\n",
- __func__);
- xtal_ref_div = 2;
- }
-
- /*Calculating Reference Clock by divding original frequency by
- * XTAL_REF_DIV.
- * At upper level, uint32_t reference_frequency =
- * dal_i2caux_get_reference_clock(as) >> 1
- * which already divided by 2. So we need x2 to get original
- * reference clock from ppll_info
- */
- hw_engine->reference_frequency =
- (arg->reference_frequency * 2) / xtal_ref_div;
-}
-
-struct i2c_engine *dal_i2c_hw_engine_dce110_create(
- const struct i2c_hw_engine_dce110_create_arg *arg)
-{
- struct i2c_hw_engine_dce110 *engine_dce10;
-
- if (!arg) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
- if (!arg->reference_frequency) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- engine_dce10 = kzalloc(sizeof(struct i2c_hw_engine_dce110),
- GFP_KERNEL);
-
- if (!engine_dce10) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- construct(engine_dce10, arg);
- return &engine_dce10->base.base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h
deleted file mode 100644
index fea2946906ed..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_HW_ENGINE_DCE110_H__
-#define __DAL_I2C_HW_ENGINE_DCE110_H__
-
-#define I2C_HW_ENGINE_COMMON_REG_LIST(id)\
- SRI(SETUP, DC_I2C_DDC, id),\
- SRI(SPEED, DC_I2C_DDC, id),\
- SR(DC_I2C_ARBITRATION),\
- SR(DC_I2C_CONTROL),\
- SR(DC_I2C_SW_STATUS),\
- SR(DC_I2C_TRANSACTION0),\
- SR(DC_I2C_TRANSACTION1),\
- SR(DC_I2C_TRANSACTION2),\
- SR(DC_I2C_TRANSACTION3),\
- SR(DC_I2C_DATA),\
- SR(MICROSECOND_TIME_BASE_DIV)
-
-#define I2C_SF(reg_name, field_name, post_fix)\
- .field_name = reg_name ## __ ## field_name ## post_fix
-
-#define I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh)\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY, mask_sh),\
- I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, mask_sh),\
- I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\
- I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_PRIORITY, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_GO, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_SEND_RESET, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_TRANSACTION_COUNT, mask_sh),\
- I2C_SF(DC_I2C_CONTROL, DC_I2C_DDC_SELECT, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE, mask_sh),\
- I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD, mask_sh),\
- I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_STOPPED_ON_NACK, mask_sh),\
- I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_TIMEOUT, mask_sh),\
- I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_ABORTED, mask_sh),\
- I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_DONE, mask_sh),\
- I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, mask_sh),\
- I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0, mask_sh),\
- I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_START0, mask_sh),\
- I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_RW0, mask_sh),\
- I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_STOP0, mask_sh),\
- I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_COUNT0, mask_sh),\
- I2C_SF(DC_I2C_DATA, DC_I2C_DATA_RW, mask_sh),\
- I2C_SF(DC_I2C_DATA, DC_I2C_DATA, mask_sh),\
- I2C_SF(DC_I2C_DATA, DC_I2C_INDEX, mask_sh),\
- I2C_SF(DC_I2C_DATA, DC_I2C_INDEX_WRITE, mask_sh),\
- I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh)
-
-#define I2C_COMMON_MASK_SH_LIST_DCE100(mask_sh)\
- I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh)
-
-#define I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh)\
- I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh),\
- I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL, mask_sh)
-
-struct dce110_i2c_hw_engine_shift {
- uint8_t DC_I2C_DDC1_ENABLE;
- uint8_t DC_I2C_DDC1_TIME_LIMIT;
- uint8_t DC_I2C_DDC1_DATA_DRIVE_EN;
- uint8_t DC_I2C_DDC1_CLK_DRIVE_EN;
- uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL;
- uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
- uint8_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
- uint8_t DC_I2C_SW_DONE_USING_I2C_REG;
- uint8_t DC_I2C_NO_QUEUED_SW_GO;
- uint8_t DC_I2C_SW_PRIORITY;
- uint8_t DC_I2C_SOFT_RESET;
- uint8_t DC_I2C_SW_STATUS_RESET;
- uint8_t DC_I2C_GO;
- uint8_t DC_I2C_SEND_RESET;
- uint8_t DC_I2C_TRANSACTION_COUNT;
- uint8_t DC_I2C_DDC_SELECT;
- uint8_t DC_I2C_DDC1_PRESCALE;
- uint8_t DC_I2C_DDC1_THRESHOLD;
- uint8_t DC_I2C_DDC1_START_STOP_TIMING_CNTL;
- uint8_t DC_I2C_SW_STOPPED_ON_NACK;
- uint8_t DC_I2C_SW_TIMEOUT;
- uint8_t DC_I2C_SW_ABORTED;
- uint8_t DC_I2C_SW_DONE;
- uint8_t DC_I2C_SW_STATUS;
- uint8_t DC_I2C_STOP_ON_NACK0;
- uint8_t DC_I2C_START0;
- uint8_t DC_I2C_RW0;
- uint8_t DC_I2C_STOP0;
- uint8_t DC_I2C_COUNT0;
- uint8_t DC_I2C_DATA_RW;
- uint8_t DC_I2C_DATA;
- uint8_t DC_I2C_INDEX;
- uint8_t DC_I2C_INDEX_WRITE;
- uint8_t XTAL_REF_DIV;
-};
-
-struct dce110_i2c_hw_engine_mask {
- uint32_t DC_I2C_DDC1_ENABLE;
- uint32_t DC_I2C_DDC1_TIME_LIMIT;
- uint32_t DC_I2C_DDC1_DATA_DRIVE_EN;
- uint32_t DC_I2C_DDC1_CLK_DRIVE_EN;
- uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL;
- uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
- uint32_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
- uint32_t DC_I2C_SW_DONE_USING_I2C_REG;
- uint32_t DC_I2C_NO_QUEUED_SW_GO;
- uint32_t DC_I2C_SW_PRIORITY;
- uint32_t DC_I2C_SOFT_RESET;
- uint32_t DC_I2C_SW_STATUS_RESET;
- uint32_t DC_I2C_GO;
- uint32_t DC_I2C_SEND_RESET;
- uint32_t DC_I2C_TRANSACTION_COUNT;
- uint32_t DC_I2C_DDC_SELECT;
- uint32_t DC_I2C_DDC1_PRESCALE;
- uint32_t DC_I2C_DDC1_THRESHOLD;
- uint32_t DC_I2C_DDC1_START_STOP_TIMING_CNTL;
- uint32_t DC_I2C_SW_STOPPED_ON_NACK;
- uint32_t DC_I2C_SW_TIMEOUT;
- uint32_t DC_I2C_SW_ABORTED;
- uint32_t DC_I2C_SW_DONE;
- uint32_t DC_I2C_SW_STATUS;
- uint32_t DC_I2C_STOP_ON_NACK0;
- uint32_t DC_I2C_START0;
- uint32_t DC_I2C_RW0;
- uint32_t DC_I2C_STOP0;
- uint32_t DC_I2C_COUNT0;
- uint32_t DC_I2C_DATA_RW;
- uint32_t DC_I2C_DATA;
- uint32_t DC_I2C_INDEX;
- uint32_t DC_I2C_INDEX_WRITE;
- uint32_t XTAL_REF_DIV;
-};
-
-struct dce110_i2c_hw_engine_registers {
- uint32_t SETUP;
- uint32_t SPEED;
- uint32_t DC_I2C_ARBITRATION;
- uint32_t DC_I2C_CONTROL;
- uint32_t DC_I2C_SW_STATUS;
- uint32_t DC_I2C_TRANSACTION0;
- uint32_t DC_I2C_TRANSACTION1;
- uint32_t DC_I2C_TRANSACTION2;
- uint32_t DC_I2C_TRANSACTION3;
- uint32_t DC_I2C_DATA;
- uint32_t MICROSECOND_TIME_BASE_DIV;
-};
-
-struct i2c_hw_engine_dce110 {
- struct i2c_hw_engine base;
- const struct dce110_i2c_hw_engine_registers *regs;
- const struct dce110_i2c_hw_engine_shift *i2c_shift;
- const struct dce110_i2c_hw_engine_mask *i2c_mask;
- struct {
- uint32_t DC_I2C_DDCX_SETUP;
- uint32_t DC_I2C_DDCX_SPEED;
- } addr;
- uint32_t engine_id;
- /* expressed in kilohertz */
- uint32_t reference_frequency;
- /* number of bytes currently used in HW buffer */
- uint32_t buffer_used_bytes;
- /* number of bytes used for write transaction in HW buffer
- * - this will be used as the index to read from*/
- uint32_t buffer_used_write;
- /* number of pending transactions (before GO) */
- uint32_t transaction_count;
- uint32_t engine_keep_power_up_count;
- uint32_t i2_setup_time_limit;
-};
-
-struct i2c_hw_engine_dce110_create_arg {
- uint32_t engine_id;
- uint32_t reference_frequency;
- uint32_t default_speed;
- struct dc_context *ctx;
- const struct dce110_i2c_hw_engine_registers *regs;
- const struct dce110_i2c_hw_engine_shift *i2c_shift;
- const struct dce110_i2c_hw_engine_mask *i2c_mask;
-};
-
-struct i2c_engine *dal_i2c_hw_engine_dce110_create(
- const struct i2c_hw_engine_dce110_create_arg *arg);
-
-enum {
- I2C_SETUP_TIME_LIMIT_DCE = 255,
- I2C_SETUP_TIME_LIMIT_DCN = 3,
- I2C_HW_BUFFER_SIZE = 538,
- I2C_SEND_RESET_LENGTH_9 = 9,
- I2C_SEND_RESET_LENGTH_10 = 10,
-};
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c
deleted file mode 100644
index 3aa7f791e523..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_sw_engine_dce110.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-/*
- * @brief
- * Cast 'struct i2c_sw_engine *'
- * to 'struct i2c_sw_engine_dce110 *'
- */
-#define FROM_I2C_SW_ENGINE(ptr) \
- container_of((ptr), struct i2c_sw_engine_dce110, base)
-/*
- * @brief
- * Cast 'struct i2c_engine *'
- * to 'struct i2c_sw_engine_dce80 *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base))
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct i2c_sw_engine_dce80 *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-static void release_engine(
- struct engine *engine)
-{
-}
-
-static void destruct(
- struct i2c_sw_engine_dce110 *engine)
-{
- dal_i2c_sw_engine_destruct(&engine->base);
-}
-
-static void destroy(
- struct i2c_engine **engine)
-{
- struct i2c_sw_engine_dce110 *sw_engine = FROM_I2C_ENGINE(*engine);
-
- destruct(sw_engine);
-
- kfree(sw_engine);
-
- *engine = NULL;
-}
-
-static bool acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc_handle)
-{
- return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle);
-}
-
-static const struct i2c_engine_funcs i2c_engine_funcs = {
- .acquire_engine = acquire_engine,
- .destroy = destroy,
- .get_speed = dal_i2c_sw_engine_get_speed,
- .set_speed = dal_i2c_sw_engine_set_speed,
- .setup_engine = dal_i2c_engine_setup_i2c_engine,
- .submit_channel_request = dal_i2c_sw_engine_submit_channel_request,
- .process_channel_reply = dal_i2c_engine_process_channel_reply,
- .get_channel_status = dal_i2c_sw_engine_get_channel_status,
-};
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .get_engine_type = dal_i2c_sw_engine_get_engine_type,
- .acquire = dal_i2c_engine_acquire,
- .submit_request = dal_i2c_sw_engine_submit_request,
-};
-
-static void construct(
- struct i2c_sw_engine_dce110 *engine_dce110,
- const struct i2c_sw_engine_dce110_create_arg *arg_dce110)
-{
- struct i2c_sw_engine_create_arg arg_base;
-
- arg_base.ctx = arg_dce110->ctx;
- arg_base.default_speed = arg_dce110->default_speed;
-
- dal_i2c_sw_engine_construct(&engine_dce110->base, &arg_base);
-
- /*struct engine struct engine_funcs*/
- engine_dce110->base.base.base.funcs = &engine_funcs;
- /*struct i2c_engine struct i2c_engine_funcs*/
- engine_dce110->base.base.funcs = &i2c_engine_funcs;
- engine_dce110->base.default_speed = arg_dce110->default_speed;
- engine_dce110->engine_id = arg_dce110->engine_id;
-}
-
-struct i2c_engine *dal_i2c_sw_engine_dce110_create(
- const struct i2c_sw_engine_dce110_create_arg *arg)
-{
- struct i2c_sw_engine_dce110 *engine_dce110;
-
- if (!arg) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- engine_dce110 = kzalloc(sizeof(struct i2c_sw_engine_dce110),
- GFP_KERNEL);
-
- if (!engine_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- construct(engine_dce110, arg);
- return &engine_dce110->base.base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c
deleted file mode 100644
index 1d748ac1d6d6..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-/*
- * Header of this unit
- */
-#include "i2caux_dce110.h"
-
-#include "i2c_sw_engine_dce110.h"
-#include "i2c_hw_engine_dce110.h"
-#include "aux_engine_dce110.h"
-#include "../../dc.h"
-#include "dc_types.h"
-
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-/*cast pointer to struct i2caux TO pointer to struct i2caux_dce110*/
-#define FROM_I2C_AUX(ptr) \
- container_of((ptr), struct i2caux_dce110, base)
-
-static void destruct(
- struct i2caux_dce110 *i2caux_dce110)
-{
- dal_i2caux_destruct(&i2caux_dce110->base);
-}
-
-static void destroy(
- struct i2caux **i2c_engine)
-{
- struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(*i2c_engine);
-
- destruct(i2caux_dce110);
-
- kfree(i2caux_dce110);
-
- *i2c_engine = NULL;
-}
-
-static struct i2c_engine *acquire_i2c_hw_engine(
- struct i2caux *i2caux,
- struct ddc *ddc)
-{
- struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux);
-
- struct i2c_engine *engine = NULL;
- /* generic hw engine is not used for EDID read
- * It may be needed for external i2c device, like thermal chip,
- * TODO will be implemented when needed.
- * check dce80 bool non_generic for generic hw engine;
- */
-
- if (!ddc)
- return NULL;
-
- if (ddc->hw_info.hw_supported) {
- enum gpio_ddc_line line = dal_ddc_get_line(ddc);
-
- if (line < GPIO_DDC_LINE_COUNT)
- engine = i2caux->i2c_hw_engines[line];
- }
-
- if (!engine)
- return NULL;
-
- if (!i2caux_dce110->i2c_hw_buffer_in_use &&
- engine->base.funcs->acquire(&engine->base, ddc)) {
- i2caux_dce110->i2c_hw_buffer_in_use = true;
- return engine;
- }
-
- return NULL;
-}
-
-static void release_engine(
- struct i2caux *i2caux,
- struct engine *engine)
-{
- struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux);
-
- if (engine->funcs->get_engine_type(engine) ==
- I2CAUX_ENGINE_TYPE_I2C_DDC_HW)
- i2caux_dce110->i2c_hw_buffer_in_use = false;
-
- dal_i2caux_release_engine(i2caux, engine);
-}
-
-static const enum gpio_ddc_line hw_ddc_lines[] = {
- GPIO_DDC_LINE_DDC1,
- GPIO_DDC_LINE_DDC2,
- GPIO_DDC_LINE_DDC3,
- GPIO_DDC_LINE_DDC4,
- GPIO_DDC_LINE_DDC5,
- GPIO_DDC_LINE_DDC6,
-};
-
-static const enum gpio_ddc_line hw_aux_lines[] = {
- GPIO_DDC_LINE_DDC1,
- GPIO_DDC_LINE_DDC2,
- GPIO_DDC_LINE_DDC3,
- GPIO_DDC_LINE_DDC4,
- GPIO_DDC_LINE_DDC5,
- GPIO_DDC_LINE_DDC6,
-};
-
-/* function table */
-static const struct i2caux_funcs i2caux_funcs = {
- .destroy = destroy,
- .acquire_i2c_hw_engine = acquire_i2c_hw_engine,
- .release_engine = release_engine,
- .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine,
- .acquire_aux_engine = dal_i2caux_acquire_aux_engine,
-};
-
-#include "dce/dce_11_0_d.h"
-#include "dce/dce_11_0_sh_mask.h"
-
-/* set register offset */
-#define SR(reg_name)\
- .reg_name = mm ## reg_name
-
-/* set register offset with instance */
-#define SRI(reg_name, block, id)\
- .reg_name = mm ## block ## id ## _ ## reg_name
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = AUX_CONTROL__AUX_RESET_MASK \
-}
-
-#define hw_engine_regs(id)\
-{\
- I2C_HW_ENGINE_COMMON_REG_LIST(id) \
-}
-
-static const struct dce110_aux_registers dce110_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5)
-};
-
-static const struct dce110_i2c_hw_engine_registers i2c_hw_engine_regs[] = {
- hw_engine_regs(1),
- hw_engine_regs(2),
- hw_engine_regs(3),
- hw_engine_regs(4),
- hw_engine_regs(5),
- hw_engine_regs(6)
-};
-
-static const struct dce110_i2c_hw_engine_shift i2c_shift = {
- I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT)
-};
-
-static const struct dce110_i2c_hw_engine_mask i2c_mask = {
- I2C_COMMON_MASK_SH_LIST_DCE110(_MASK)
-};
-
-void dal_i2caux_dce110_construct(
- struct i2caux_dce110 *i2caux_dce110,
- struct dc_context *ctx,
- unsigned int num_i2caux_inst,
- const struct dce110_aux_registers aux_regs[],
- const struct dce110_i2c_hw_engine_registers i2c_hw_engine_regs[],
- const struct dce110_i2c_hw_engine_shift *i2c_shift,
- const struct dce110_i2c_hw_engine_mask *i2c_mask)
-{
- uint32_t i = 0;
- uint32_t reference_frequency = 0;
- bool use_i2c_sw_engine = false;
- struct i2caux *base = NULL;
- /*TODO: For CZ bring up, if dal_i2caux_get_reference_clock
- * does not return 48KHz, we need hard coded for 48Khz.
- * Some BIOS setting incorrect cause this
- * For production, we always get value from BIOS*/
- reference_frequency =
- dal_i2caux_get_reference_clock(ctx->dc_bios) >> 1;
-
- base = &i2caux_dce110->base;
-
- dal_i2caux_construct(base, ctx);
-
- i2caux_dce110->base.funcs = &i2caux_funcs;
- i2caux_dce110->i2c_hw_buffer_in_use = false;
- /* Create I2C engines (DDC lines per connector)
- * different I2C/AUX usage cases, DDC, Generic GPIO, AUX.
- */
- do {
- enum gpio_ddc_line line_id = hw_ddc_lines[i];
-
- struct i2c_hw_engine_dce110_create_arg hw_arg_dce110;
-
- if (use_i2c_sw_engine) {
- struct i2c_sw_engine_dce110_create_arg sw_arg;
-
- sw_arg.engine_id = i;
- sw_arg.default_speed = base->default_i2c_sw_speed;
- sw_arg.ctx = ctx;
- base->i2c_sw_engines[line_id] =
- dal_i2c_sw_engine_dce110_create(&sw_arg);
- }
-
- hw_arg_dce110.engine_id = i;
- hw_arg_dce110.reference_frequency = reference_frequency;
- hw_arg_dce110.default_speed = base->default_i2c_hw_speed;
- hw_arg_dce110.ctx = ctx;
- hw_arg_dce110.regs = &i2c_hw_engine_regs[i];
- hw_arg_dce110.i2c_shift = i2c_shift;
- hw_arg_dce110.i2c_mask = i2c_mask;
-
- base->i2c_hw_engines[line_id] =
- dal_i2c_hw_engine_dce110_create(&hw_arg_dce110);
- if (base->i2c_hw_engines[line_id] != NULL) {
- switch (ctx->dce_version) {
- case DCN_VERSION_1_0:
- base->i2c_hw_engines[line_id]->setup_limit =
- I2C_SETUP_TIME_LIMIT_DCN;
- base->i2c_hw_engines[line_id]->send_reset_length = 0;
- break;
- default:
- base->i2c_hw_engines[line_id]->setup_limit =
- I2C_SETUP_TIME_LIMIT_DCE;
- base->i2c_hw_engines[line_id]->send_reset_length = 0;
- break;
- }
- }
- ++i;
- } while (i < num_i2caux_inst);
-
- /* Create AUX engines for all lines which has assisted HW AUX
- * 'i' (loop counter) used as DDC/AUX engine_id */
-
- i = 0;
-
- do {
- enum gpio_ddc_line line_id = hw_aux_lines[i];
-
- struct aux_engine_dce110_init_data aux_init_data;
-
- aux_init_data.engine_id = i;
- aux_init_data.timeout_period = base->aux_timeout_period;
- aux_init_data.ctx = ctx;
- aux_init_data.regs = &aux_regs[i];
-
- base->aux_engines[line_id] =
- dal_aux_engine_dce110_create(&aux_init_data);
-
- ++i;
- } while (i < num_i2caux_inst);
-
- /*TODO Generic I2C SW and HW*/
-}
-
-/*
- * dal_i2caux_dce110_create
- *
- * @brief
- * public interface to allocate memory for DCE11 I2CAUX
- *
- * @param
- * struct adapter_service *as - [in]
- * struct dc_context *ctx - [in]
- *
- * @return
- * pointer to the base struct of DCE11 I2CAUX
- */
-struct i2caux *dal_i2caux_dce110_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce110 *i2caux_dce110 =
- kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL);
-
- if (!i2caux_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- dal_i2caux_dce110_construct(i2caux_dce110,
- ctx,
- ARRAY_SIZE(dce110_aux_regs),
- dce110_aux_regs,
- i2c_hw_engine_regs,
- &i2c_shift,
- &i2c_mask);
- return &i2caux_dce110->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h
deleted file mode 100644
index d3d8cc58666a..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_AUX_DCE110_H__
-#define __DAL_I2C_AUX_DCE110_H__
-
-#include "../i2caux.h"
-
-struct i2caux_dce110 {
- struct i2caux base;
- /* indicate the I2C HW circular buffer is in use */
- bool i2c_hw_buffer_in_use;
-};
-
-struct dce110_aux_registers;
-struct dce110_i2c_hw_engine_registers;
-struct dce110_i2c_hw_engine_shift;
-struct dce110_i2c_hw_engine_mask;
-
-struct i2caux *dal_i2caux_dce110_create(
- struct dc_context *ctx);
-
-void dal_i2caux_dce110_construct(
- struct i2caux_dce110 *i2caux_dce110,
- struct dc_context *ctx,
- unsigned int num_i2caux_inst,
- const struct dce110_aux_registers *aux_regs,
- const struct dce110_i2c_hw_engine_registers *i2c_hw_engine_regs,
- const struct dce110_i2c_hw_engine_shift *i2c_shift,
- const struct dce110_i2c_hw_engine_mask *i2c_mask);
-
-#endif /* __DAL_I2C_AUX_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c
deleted file mode 100644
index a9db04738724..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-#include "../dce110/i2caux_dce110.h"
-#include "i2caux_dce112.h"
-
-#include "../dce110/aux_engine_dce110.h"
-
-#include "../dce110/i2c_hw_engine_dce110.h"
-
-#include "dce/dce_11_2_d.h"
-#include "dce/dce_11_2_sh_mask.h"
-
-/* set register offset */
-#define SR(reg_name)\
- .reg_name = mm ## reg_name
-
-/* set register offset with instance */
-#define SRI(reg_name, block, id)\
- .reg_name = mm ## block ## id ## _ ## reg_name
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = AUX_CONTROL__AUX_RESET_MASK \
-}
-
-#define hw_engine_regs(id)\
-{\
- I2C_HW_ENGINE_COMMON_REG_LIST(id) \
-}
-
-static const struct dce110_aux_registers dce112_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5),
-};
-
-static const struct dce110_i2c_hw_engine_registers dce112_hw_engine_regs[] = {
- hw_engine_regs(1),
- hw_engine_regs(2),
- hw_engine_regs(3),
- hw_engine_regs(4),
- hw_engine_regs(5),
- hw_engine_regs(6)
-};
-
-static const struct dce110_i2c_hw_engine_shift i2c_shift = {
- I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT)
-};
-
-static const struct dce110_i2c_hw_engine_mask i2c_mask = {
- I2C_COMMON_MASK_SH_LIST_DCE110(_MASK)
-};
-
-static void construct(
- struct i2caux_dce110 *i2caux_dce110,
- struct dc_context *ctx)
-{
- dal_i2caux_dce110_construct(i2caux_dce110,
- ctx,
- ARRAY_SIZE(dce112_aux_regs),
- dce112_aux_regs,
- dce112_hw_engine_regs,
- &i2c_shift,
- &i2c_mask);
-}
-
-/*
- * dal_i2caux_dce110_create
- *
- * @brief
- * public interface to allocate memory for DCE11 I2CAUX
- *
- * @param
- * struct adapter_service *as - [in]
- * struct dc_context *ctx - [in]
- *
- * @return
- * pointer to the base struct of DCE11 I2CAUX
- */
-struct i2caux *dal_i2caux_dce112_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce110 *i2caux_dce110 =
- kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL);
-
- if (!i2caux_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- construct(i2caux_dce110, ctx);
- return &i2caux_dce110->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h
deleted file mode 100644
index 8d35453c25b6..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_AUX_DCE112_H__
-#define __DAL_I2C_AUX_DCE112_H__
-
-struct i2caux *dal_i2caux_dce112_create(
- struct dc_context *ctx);
-
-#endif /* __DAL_I2C_AUX_DCE112_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c
deleted file mode 100644
index 6a4f344c1db4..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#include "dm_services.h"
-
-#include "include/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-#include "../dce110/i2c_hw_engine_dce110.h"
-#include "../dce110/aux_engine_dce110.h"
-#include "../dce110/i2caux_dce110.h"
-
-#include "dce/dce_12_0_offset.h"
-#include "dce/dce_12_0_sh_mask.h"
-#include "soc15_hw_ip.h"
-#include "vega10_ip_offset.h"
-
-/* begin *********************
- * macros to expend register list macro defined in HW object header file */
-
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-/* compile time expand base address. */
-#define BASE(seg) \
- BASE_INNER(seg)
-
-#define SR(reg_name)\
- .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
- mm ## reg_name
-
-#define SRI(reg_name, block, id)\
- .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
- mm ## block ## id ## _ ## reg_name
-/* macros to expend register list macro defined in HW object header file
- * end *********************/
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK \
-}
-
-static const struct dce110_aux_registers dce120_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5),
-};
-
-#define hw_engine_regs(id)\
-{\
- I2C_HW_ENGINE_COMMON_REG_LIST(id) \
-}
-
-static const struct dce110_i2c_hw_engine_registers dce120_hw_engine_regs[] = {
- hw_engine_regs(1),
- hw_engine_regs(2),
- hw_engine_regs(3),
- hw_engine_regs(4),
- hw_engine_regs(5),
- hw_engine_regs(6)
-};
-
-static const struct dce110_i2c_hw_engine_shift i2c_shift = {
- I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT)
-};
-
-static const struct dce110_i2c_hw_engine_mask i2c_mask = {
- I2C_COMMON_MASK_SH_LIST_DCE110(_MASK)
-};
-
-struct i2caux *dal_i2caux_dce120_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce110 *i2caux_dce110 =
- kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL);
-
- if (!i2caux_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- dal_i2caux_dce110_construct(i2caux_dce110,
- ctx,
- ARRAY_SIZE(dce120_aux_regs),
- dce120_aux_regs,
- dce120_hw_engine_regs,
- &i2c_shift,
- &i2c_mask);
- return &i2caux_dce110->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c
deleted file mode 100644
index fd0832dd2c75..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c
+++ /dev/null
@@ -1,875 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_hw_engine.h"
-#include "../i2c_generic_hw_engine.h"
-/*
- * Header of this unit
- */
-
-#include "i2c_hw_engine_dce80.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-#include "dce/dce_8_0_d.h"
-#include "dce/dce_8_0_sh_mask.h"
-/*
- * This unit
- */
-
-enum dc_i2c_status {
- DC_I2C_STATUS__DC_I2C_STATUS_IDLE,
- DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW,
- DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW
-};
-
-enum dc_i2c_arbitration {
- DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL,
- DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH
-};
-
-enum {
- /* No timeout in HW
- * (timeout implemented in SW by querying status) */
- I2C_SETUP_TIME_LIMIT = 255,
- I2C_HW_BUFFER_SIZE = 144
-};
-
-/*
- * @brief
- * Cast 'struct i2c_hw_engine *'
- * to 'struct i2c_hw_engine_dce80 *'
- */
-#define FROM_I2C_HW_ENGINE(ptr) \
- container_of((ptr), struct i2c_hw_engine_dce80, base)
-
-/*
- * @brief
- * Cast pointer to 'struct i2c_engine *'
- * to pointer to 'struct i2c_hw_engine_dce80 *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base))
-
-/*
- * @brief
- * Cast pointer to 'struct engine *'
- * to 'pointer to struct i2c_hw_engine_dce80 *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-static void disable_i2c_hw_engine(
- struct i2c_hw_engine_dce80 *engine)
-{
- const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
- uint32_t value = 0;
-
- struct dc_context *ctx = NULL;
-
- ctx = engine->base.base.base.ctx;
-
- value = dm_read_reg(ctx, addr);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_ENABLE);
-
- dm_write_reg(ctx, addr, value);
-}
-
-static void release_engine(
- struct engine *engine)
-{
- struct i2c_hw_engine_dce80 *hw_engine = FROM_ENGINE(engine);
-
- struct i2c_engine *base = NULL;
- bool safe_to_reset;
- uint32_t value = 0;
-
- base = &hw_engine->base.base;
-
- /* Restore original HW engine speed */
-
- base->funcs->set_speed(base, hw_engine->base.original_speed);
-
- /* Release I2C */
- {
- value = dm_read_reg(engine->ctx, mmDC_I2C_ARBITRATION);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_ARBITRATION,
- DC_I2C_SW_DONE_USING_I2C_REG);
-
- dm_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value);
- }
-
- /* Reset HW engine */
- {
- uint32_t i2c_sw_status = 0;
-
- value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
-
- i2c_sw_status = get_reg_field_value(
- value,
- DC_I2C_SW_STATUS,
- DC_I2C_SW_STATUS);
- /* if used by SW, safe to reset */
- safe_to_reset = (i2c_sw_status == 1);
- }
- {
- value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL);
-
- if (safe_to_reset)
- set_reg_field_value(
- value,
- 1,
- DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_CONTROL,
- DC_I2C_SW_STATUS_RESET);
-
- dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value);
- }
-
- /* HW I2c engine - clock gating feature */
- if (!hw_engine->engine_keep_power_up_count)
- disable_i2c_hw_engine(hw_engine);
-}
-
-static void destruct(
- struct i2c_hw_engine_dce80 *engine)
-{
- dal_i2c_hw_engine_destruct(&engine->base);
-}
-
-static void destroy(
- struct i2c_engine **i2c_engine)
-{
- struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(*i2c_engine);
-
- destruct(engine);
-
- kfree(engine);
-
- *i2c_engine = NULL;
-}
-
-static bool setup_engine(
- struct i2c_engine *i2c_engine)
-{
- uint32_t value = 0;
- struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine);
-
- /* Program pin select */
- {
- const uint32_t addr = mmDC_I2C_CONTROL;
-
- value = dm_read_reg(i2c_engine->base.ctx, addr);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_GO);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SEND_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SW_STATUS_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_TRANSACTION_COUNT);
-
- set_reg_field_value(
- value,
- engine->engine_id,
- DC_I2C_CONTROL,
- DC_I2C_DDC_SELECT);
-
- dm_write_reg(i2c_engine->base.ctx, addr, value);
- }
-
- /* Program time limit */
- {
- const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
-
- value = dm_read_reg(i2c_engine->base.ctx, addr);
-
- set_reg_field_value(
- value,
- I2C_SETUP_TIME_LIMIT,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_TIME_LIMIT);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_ENABLE);
-
- dm_write_reg(i2c_engine->base.ctx, addr, value);
- }
-
- /* Program HW priority
- * set to High - interrupt software I2C at any time
- * Enable restart of SW I2C that was interrupted by HW
- * disable queuing of software while I2C is in use by HW */
- {
- value = dm_read_reg(i2c_engine->base.ctx,
- mmDC_I2C_ARBITRATION);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_ARBITRATION,
- DC_I2C_NO_QUEUED_SW_GO);
-
- set_reg_field_value(
- value,
- DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL,
- DC_I2C_ARBITRATION,
- DC_I2C_SW_PRIORITY);
-
- dm_write_reg(i2c_engine->base.ctx,
- mmDC_I2C_ARBITRATION, value);
- }
-
- return true;
-}
-
-static uint32_t get_speed(
- const struct i2c_engine *i2c_engine)
-{
- const struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine);
-
- const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED;
-
- uint32_t pre_scale = 0;
-
- uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr);
-
- pre_scale = get_reg_field_value(
- value,
- DC_I2C_DDC1_SPEED,
- DC_I2C_DDC1_PRESCALE);
-
- /* [anaumov] it seems following is unnecessary */
- /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/
-
- return pre_scale ?
- engine->reference_frequency / pre_scale :
- engine->base.default_speed;
-}
-
-static void set_speed(
- struct i2c_engine *i2c_engine,
- uint32_t speed)
-{
- struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine);
-
- if (speed) {
- const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED;
-
- uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr);
-
- set_reg_field_value(
- value,
- engine->reference_frequency / speed,
- DC_I2C_DDC1_SPEED,
- DC_I2C_DDC1_PRESCALE);
-
- set_reg_field_value(
- value,
- 2,
- DC_I2C_DDC1_SPEED,
- DC_I2C_DDC1_THRESHOLD);
-
- dm_write_reg(i2c_engine->base.ctx, addr, value);
- }
-}
-
-static inline void reset_hw_engine(struct engine *engine)
-{
- uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_CONTROL,
- DC_I2C_SW_STATUS_RESET);
-
- dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value);
-}
-
-static bool is_hw_busy(struct engine *engine)
-{
- uint32_t i2c_sw_status = 0;
-
- uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
-
- i2c_sw_status = get_reg_field_value(
- value,
- DC_I2C_SW_STATUS,
- DC_I2C_SW_STATUS);
-
- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
- return false;
-
- reset_hw_engine(engine);
-
- value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
-
- i2c_sw_status = get_reg_field_value(
- value,
- DC_I2C_SW_STATUS,
- DC_I2C_SW_STATUS);
-
- return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
-}
-
-/*
- * @brief
- * DC_GPIO_DDC MM register offsets
- */
-static const uint32_t transaction_addr[] = {
- mmDC_I2C_TRANSACTION0,
- mmDC_I2C_TRANSACTION1,
- mmDC_I2C_TRANSACTION2,
- mmDC_I2C_TRANSACTION3
-};
-
-static bool process_transaction(
- struct i2c_hw_engine_dce80 *engine,
- struct i2c_request_transaction_data *request)
-{
- uint32_t length = request->length;
- uint8_t *buffer = request->data;
-
- bool last_transaction = false;
- uint32_t value = 0;
-
- struct dc_context *ctx = NULL;
-
- ctx = engine->base.base.base.ctx;
-
- {
- const uint32_t addr =
- transaction_addr[engine->transaction_count];
-
- value = dm_read_reg(ctx, addr);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_TRANSACTION0,
- DC_I2C_STOP_ON_NACK0);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_TRANSACTION0,
- DC_I2C_START0);
-
- if ((engine->transaction_count == 3) ||
- (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
- (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) {
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_TRANSACTION0,
- DC_I2C_STOP0);
-
- last_transaction = true;
- } else
- set_reg_field_value(
- value,
- 0,
- DC_I2C_TRANSACTION0,
- DC_I2C_STOP0);
-
- set_reg_field_value(
- value,
- (0 != (request->action &
- I2CAUX_TRANSACTION_ACTION_I2C_READ)),
- DC_I2C_TRANSACTION0,
- DC_I2C_RW0);
-
- set_reg_field_value(
- value,
- length,
- DC_I2C_TRANSACTION0,
- DC_I2C_COUNT0);
-
- dm_write_reg(ctx, addr, value);
- }
-
- /* Write the I2C address and I2C data
- * into the hardware circular buffer, one byte per entry.
- * As an example, the 7-bit I2C slave address for CRT monitor
- * for reading DDC/EDID information is 0b1010001.
- * For an I2C send operation, the LSB must be programmed to 0;
- * for I2C receive operation, the LSB must be programmed to 1. */
-
- {
- value = 0;
-
- set_reg_field_value(
- value,
- false,
- DC_I2C_DATA,
- DC_I2C_DATA_RW);
-
- set_reg_field_value(
- value,
- request->address,
- DC_I2C_DATA,
- DC_I2C_DATA);
-
- if (engine->transaction_count == 0) {
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DATA,
- DC_I2C_INDEX);
-
- /*enable index write*/
- set_reg_field_value(
- value,
- 1,
- DC_I2C_DATA,
- DC_I2C_INDEX_WRITE);
- }
-
- dm_write_reg(ctx, mmDC_I2C_DATA, value);
-
- if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) {
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DATA,
- DC_I2C_INDEX_WRITE);
-
- while (length) {
-
- set_reg_field_value(
- value,
- *buffer++,
- DC_I2C_DATA,
- DC_I2C_DATA);
-
- dm_write_reg(ctx, mmDC_I2C_DATA, value);
- --length;
- }
- }
- }
-
- ++engine->transaction_count;
- engine->buffer_used_bytes += length + 1;
-
- return last_transaction;
-}
-
-static void execute_transaction(
- struct i2c_hw_engine_dce80 *engine)
-{
- uint32_t value = 0;
- struct dc_context *ctx = NULL;
-
- ctx = engine->base.base.base.ctx;
-
- {
- const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
-
- value = dm_read_reg(ctx, addr);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_DATA_DRIVE_EN);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_CLK_DRIVE_EN);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_DATA_DRIVE_SEL);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_INTRA_TRANSACTION_DELAY);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_DDC1_SETUP,
- DC_I2C_DDC1_INTRA_BYTE_DELAY);
-
- dm_write_reg(ctx, addr, value);
- }
-
- {
- const uint32_t addr = mmDC_I2C_CONTROL;
-
- value = dm_read_reg(ctx, addr);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SOFT_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SW_STATUS_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_SEND_RESET);
-
- set_reg_field_value(
- value,
- 0,
- DC_I2C_CONTROL,
- DC_I2C_GO);
-
- set_reg_field_value(
- value,
- engine->transaction_count - 1,
- DC_I2C_CONTROL,
- DC_I2C_TRANSACTION_COUNT);
-
- dm_write_reg(ctx, addr, value);
- }
-
- /* start I2C transfer */
- {
- const uint32_t addr = mmDC_I2C_CONTROL;
-
- value = dm_read_reg(ctx, addr);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_CONTROL,
- DC_I2C_GO);
-
- dm_write_reg(ctx, addr, value);
- }
-
- /* all transactions were executed and HW buffer became empty
- * (even though it actually happens when status becomes DONE) */
- engine->transaction_count = 0;
- engine->buffer_used_bytes = 0;
-}
-
-static void submit_channel_request(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *request)
-{
- request->status = I2C_CHANNEL_OPERATION_SUCCEEDED;
-
- if (!process_transaction(FROM_I2C_ENGINE(engine), request))
- return;
-
- if (is_hw_busy(&engine->base)) {
- request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
- return;
- }
-
- execute_transaction(FROM_I2C_ENGINE(engine));
-}
-
-static void process_channel_reply(
- struct i2c_engine *engine,
- struct i2c_reply_transaction_data *reply)
-{
- uint32_t length = reply->length;
- uint8_t *buffer = reply->data;
-
- uint32_t value = 0;
-
- /*set index*/
- set_reg_field_value(
- value,
- length - 1,
- DC_I2C_DATA,
- DC_I2C_INDEX);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_DATA,
- DC_I2C_DATA_RW);
-
- set_reg_field_value(
- value,
- 1,
- DC_I2C_DATA,
- DC_I2C_INDEX_WRITE);
-
- dm_write_reg(engine->base.ctx, mmDC_I2C_DATA, value);
-
- while (length) {
- /* after reading the status,
- * if the I2C operation executed successfully
- * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller
- * should read data bytes from I2C circular data buffer */
-
- value = dm_read_reg(engine->base.ctx, mmDC_I2C_DATA);
-
- *buffer++ = get_reg_field_value(
- value,
- DC_I2C_DATA,
- DC_I2C_DATA);
-
- --length;
- }
-}
-
-static enum i2c_channel_operation_result get_channel_status(
- struct i2c_engine *engine,
- uint8_t *returned_bytes)
-{
- uint32_t i2c_sw_status = 0;
- uint32_t value = dm_read_reg(engine->base.ctx, mmDC_I2C_SW_STATUS);
-
- i2c_sw_status = get_reg_field_value(
- value,
- DC_I2C_SW_STATUS,
- DC_I2C_SW_STATUS);
-
- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW)
- return I2C_CHANNEL_OPERATION_ENGINE_BUSY;
- else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_STOPPED_ON_NACK_MASK)
- return I2C_CHANNEL_OPERATION_NO_RESPONSE;
- else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_TIMEOUT_MASK)
- return I2C_CHANNEL_OPERATION_TIMEOUT;
- else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_ABORTED_MASK)
- return I2C_CHANNEL_OPERATION_FAILED;
- else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_DONE_MASK)
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-
- /*
- * this is the case when HW used for communication, I2C_SW_STATUS
- * could be zero
- */
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-}
-
-static uint32_t get_hw_buffer_available_size(
- const struct i2c_hw_engine *engine)
-{
- return I2C_HW_BUFFER_SIZE -
- FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes;
-}
-
-static uint32_t get_transaction_timeout(
- const struct i2c_hw_engine *engine,
- uint32_t length)
-{
- uint32_t speed = engine->base.funcs->get_speed(&engine->base);
-
- uint32_t period_timeout;
- uint32_t num_of_clock_stretches;
-
- if (!speed)
- return 0;
-
- period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed;
-
- num_of_clock_stretches = 1 + (length << 3) + 1;
- num_of_clock_stretches +=
- (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) +
- (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1);
-
- return period_timeout * num_of_clock_stretches;
-}
-
-/*
- * @brief
- * DC_I2C_DDC1_SETUP MM register offsets
- *
- * @note
- * The indices of this offset array are DDC engine IDs
- */
-static const int32_t ddc_setup_offset[] = {
-
- mmDC_I2C_DDC1_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 1 */
- mmDC_I2C_DDC2_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 2 */
- mmDC_I2C_DDC3_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 3 */
- mmDC_I2C_DDC4_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 4 */
- mmDC_I2C_DDC5_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 5 */
- mmDC_I2C_DDC6_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 6 */
- mmDC_I2C_DDCVGA_SETUP - mmDC_I2C_DDC1_SETUP /* DDC Engine 7 */
-};
-
-/*
- * @brief
- * DC_I2C_DDC1_SPEED MM register offsets
- *
- * @note
- * The indices of this offset array are DDC engine IDs
- */
-static const int32_t ddc_speed_offset[] = {
- mmDC_I2C_DDC1_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 1 */
- mmDC_I2C_DDC2_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 2 */
- mmDC_I2C_DDC3_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 3 */
- mmDC_I2C_DDC4_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 4 */
- mmDC_I2C_DDC5_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 5 */
- mmDC_I2C_DDC6_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 6 */
- mmDC_I2C_DDCVGA_SPEED - mmDC_I2C_DDC1_SPEED /* DDC Engine 7 */
-};
-
-static const struct i2c_engine_funcs i2c_engine_funcs = {
- .destroy = destroy,
- .get_speed = get_speed,
- .set_speed = set_speed,
- .setup_engine = setup_engine,
- .submit_channel_request = submit_channel_request,
- .process_channel_reply = process_channel_reply,
- .get_channel_status = get_channel_status,
- .acquire_engine = dal_i2c_hw_engine_acquire_engine,
-};
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .get_engine_type = dal_i2c_hw_engine_get_engine_type,
- .acquire = dal_i2c_engine_acquire,
- .submit_request = dal_i2c_hw_engine_submit_request,
-};
-
-static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = {
- .get_hw_buffer_available_size =
- get_hw_buffer_available_size,
- .get_transaction_timeout =
- get_transaction_timeout,
- .wait_on_operation_result =
- dal_i2c_hw_engine_wait_on_operation_result,
-};
-
-static void construct(
- struct i2c_hw_engine_dce80 *engine,
- const struct i2c_hw_engine_dce80_create_arg *arg)
-{
- dal_i2c_hw_engine_construct(&engine->base, arg->ctx);
-
- engine->base.base.base.funcs = &engine_funcs;
- engine->base.base.funcs = &i2c_engine_funcs;
- engine->base.funcs = &i2c_hw_engine_funcs;
- engine->base.default_speed = arg->default_speed;
- engine->addr.DC_I2C_DDCX_SETUP =
- mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id];
- engine->addr.DC_I2C_DDCX_SPEED =
- mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id];
-
- engine->engine_id = arg->engine_id;
- engine->reference_frequency = arg->reference_frequency;
- engine->buffer_used_bytes = 0;
- engine->transaction_count = 0;
- engine->engine_keep_power_up_count = 1;
-}
-
-struct i2c_engine *dal_i2c_hw_engine_dce80_create(
- const struct i2c_hw_engine_dce80_create_arg *arg)
-{
- struct i2c_hw_engine_dce80 *engine;
-
- if (!arg) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- if ((arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t)) ||
- (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t)) ||
- !arg->reference_frequency) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- engine = kzalloc(sizeof(struct i2c_hw_engine_dce80), GFP_KERNEL);
-
- if (!engine) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- construct(engine, arg);
- return &engine->base.base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h
deleted file mode 100644
index 5c6116fb5479..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_HW_ENGINE_DCE80_H__
-#define __DAL_I2C_HW_ENGINE_DCE80_H__
-
-struct i2c_hw_engine_dce80 {
- struct i2c_hw_engine base;
- struct {
- uint32_t DC_I2C_DDCX_SETUP;
- uint32_t DC_I2C_DDCX_SPEED;
- } addr;
- uint32_t engine_id;
- /* expressed in kilohertz */
- uint32_t reference_frequency;
- /* number of bytes currently used in HW buffer */
- uint32_t buffer_used_bytes;
- /* number of pending transactions (before GO) */
- uint32_t transaction_count;
- uint32_t engine_keep_power_up_count;
-};
-
-struct i2c_hw_engine_dce80_create_arg {
- uint32_t engine_id;
- uint32_t reference_frequency;
- uint32_t default_speed;
- struct dc_context *ctx;
-};
-
-struct i2c_engine *dal_i2c_hw_engine_dce80_create(
- const struct i2c_hw_engine_dce80_create_arg *arg);
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c
deleted file mode 100644
index 4853ee26096a..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_sw_engine_dce80.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-#include "dce/dce_8_0_d.h"
-#include "dce/dce_8_0_sh_mask.h"
-
-/*
- * This unit
- */
-
-static const uint32_t ddc_hw_status_addr[] = {
- mmDC_I2C_DDC1_HW_STATUS,
- mmDC_I2C_DDC2_HW_STATUS,
- mmDC_I2C_DDC3_HW_STATUS,
- mmDC_I2C_DDC4_HW_STATUS,
- mmDC_I2C_DDC5_HW_STATUS,
- mmDC_I2C_DDC6_HW_STATUS,
- mmDC_I2C_DDCVGA_HW_STATUS
-};
-
-/*
- * @brief
- * Cast 'struct i2c_sw_engine *'
- * to 'struct i2c_sw_engine_dce80 *'
- */
-#define FROM_I2C_SW_ENGINE(ptr) \
- container_of((ptr), struct i2c_sw_engine_dce80, base)
-
-/*
- * @brief
- * Cast 'struct i2c_engine *'
- * to 'struct i2c_sw_engine_dce80 *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base))
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct i2c_sw_engine_dce80 *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-static void release_engine(
- struct engine *engine)
-{
-
-}
-
-static void destruct(
- struct i2c_sw_engine_dce80 *engine)
-{
- dal_i2c_sw_engine_destruct(&engine->base);
-}
-
-static void destroy(
- struct i2c_engine **engine)
-{
- struct i2c_sw_engine_dce80 *sw_engine = FROM_I2C_ENGINE(*engine);
-
- destruct(sw_engine);
-
- kfree(sw_engine);
-
- *engine = NULL;
-}
-
-static bool acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc_handle)
-{
- return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle);
-}
-
-static const struct i2c_engine_funcs i2c_engine_funcs = {
- .acquire_engine = acquire_engine,
- .destroy = destroy,
- .get_speed = dal_i2c_sw_engine_get_speed,
- .set_speed = dal_i2c_sw_engine_set_speed,
- .setup_engine = dal_i2c_engine_setup_i2c_engine,
- .submit_channel_request = dal_i2c_sw_engine_submit_channel_request,
- .process_channel_reply = dal_i2c_engine_process_channel_reply,
- .get_channel_status = dal_i2c_sw_engine_get_channel_status,
-};
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .get_engine_type = dal_i2c_sw_engine_get_engine_type,
- .acquire = dal_i2c_engine_acquire,
- .submit_request = dal_i2c_sw_engine_submit_request,
-};
-
-static void construct(
- struct i2c_sw_engine_dce80 *engine,
- const struct i2c_sw_engine_dce80_create_arg *arg)
-{
- struct i2c_sw_engine_create_arg arg_base;
-
- arg_base.ctx = arg->ctx;
- arg_base.default_speed = arg->default_speed;
-
- dal_i2c_sw_engine_construct(&engine->base, &arg_base);
-
- engine->base.base.base.funcs = &engine_funcs;
- engine->base.base.funcs = &i2c_engine_funcs;
- engine->base.default_speed = arg->default_speed;
- engine->engine_id = arg->engine_id;
-}
-
-struct i2c_engine *dal_i2c_sw_engine_dce80_create(
- const struct i2c_sw_engine_dce80_create_arg *arg)
-{
- struct i2c_sw_engine_dce80 *engine;
-
- if (!arg) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- engine = kzalloc(sizeof(struct i2c_sw_engine_dce80), GFP_KERNEL);
-
- if (!engine) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- construct(engine, arg);
- return &engine->base.base;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c
deleted file mode 100644
index ed48596dd2a5..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../i2caux.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2caux_dce80.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "i2c_sw_engine_dce80.h"
-#include "../i2c_hw_engine.h"
-#include "i2c_hw_engine_dce80.h"
-#include "../i2c_generic_hw_engine.h"
-#include "../aux_engine.h"
-
-
-#include "../dce110/aux_engine_dce110.h"
-#include "../dce110/i2caux_dce110.h"
-
-#include "dce/dce_8_0_d.h"
-#include "dce/dce_8_0_sh_mask.h"
-
-
-/* set register offset */
-#define SR(reg_name)\
- .reg_name = mm ## reg_name
-
-/* set register offset with instance */
-#define SRI(reg_name, block, id)\
- .reg_name = mm ## block ## id ## _ ## reg_name
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = 0 \
-}
-
-static const struct dce110_aux_registers dce80_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5)
-};
-
-/*
- * This unit
- */
-
-#define FROM_I2C_AUX(ptr) \
- container_of((ptr), struct i2caux_dce80, base)
-
-static void destruct(
- struct i2caux_dce80 *i2caux_dce80)
-{
- dal_i2caux_destruct(&i2caux_dce80->base);
-}
-
-static void destroy(
- struct i2caux **i2c_engine)
-{
- struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(*i2c_engine);
-
- destruct(i2caux_dce80);
-
- kfree(i2caux_dce80);
-
- *i2c_engine = NULL;
-}
-
-static struct i2c_engine *acquire_i2c_hw_engine(
- struct i2caux *i2caux,
- struct ddc *ddc)
-{
- struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(i2caux);
-
- struct i2c_engine *engine = NULL;
- bool non_generic;
-
- if (!ddc)
- return NULL;
-
- if (ddc->hw_info.hw_supported) {
- enum gpio_ddc_line line = dal_ddc_get_line(ddc);
-
- if (line < GPIO_DDC_LINE_COUNT) {
- non_generic = true;
- engine = i2caux->i2c_hw_engines[line];
- }
- }
-
- if (!engine) {
- non_generic = false;
- engine = i2caux->i2c_generic_hw_engine;
- }
-
- if (!engine)
- return NULL;
-
- if (non_generic) {
- if (!i2caux_dce80->i2c_hw_buffer_in_use &&
- engine->base.funcs->acquire(&engine->base, ddc)) {
- i2caux_dce80->i2c_hw_buffer_in_use = true;
- return engine;
- }
- } else {
- if (engine->base.funcs->acquire(&engine->base, ddc))
- return engine;
- }
-
- return NULL;
-}
-
-static void release_engine(
- struct i2caux *i2caux,
- struct engine *engine)
-{
- if (engine->funcs->get_engine_type(engine) ==
- I2CAUX_ENGINE_TYPE_I2C_DDC_HW)
- FROM_I2C_AUX(i2caux)->i2c_hw_buffer_in_use = false;
-
- dal_i2caux_release_engine(i2caux, engine);
-}
-
-static const enum gpio_ddc_line hw_ddc_lines[] = {
- GPIO_DDC_LINE_DDC1,
- GPIO_DDC_LINE_DDC2,
- GPIO_DDC_LINE_DDC3,
- GPIO_DDC_LINE_DDC4,
- GPIO_DDC_LINE_DDC5,
- GPIO_DDC_LINE_DDC6,
- GPIO_DDC_LINE_DDC_VGA
-};
-
-static const enum gpio_ddc_line hw_aux_lines[] = {
- GPIO_DDC_LINE_DDC1,
- GPIO_DDC_LINE_DDC2,
- GPIO_DDC_LINE_DDC3,
- GPIO_DDC_LINE_DDC4,
- GPIO_DDC_LINE_DDC5,
- GPIO_DDC_LINE_DDC6
-};
-
-static const struct i2caux_funcs i2caux_funcs = {
- .destroy = destroy,
- .acquire_i2c_hw_engine = acquire_i2c_hw_engine,
- .release_engine = release_engine,
- .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine,
- .acquire_aux_engine = dal_i2caux_acquire_aux_engine,
-};
-
-static void construct(
- struct i2caux_dce80 *i2caux_dce80,
- struct dc_context *ctx)
-{
- /* Entire family have I2C engine reference clock frequency
- * changed from XTALIN (27) to XTALIN/2 (13.5) */
-
- struct i2caux *base = &i2caux_dce80->base;
-
- uint32_t reference_frequency =
- dal_i2caux_get_reference_clock(ctx->dc_bios) >> 1;
-
- /*bool use_i2c_sw_engine = dal_adapter_service_is_feature_supported(as,
- FEATURE_RESTORE_USAGE_I2C_SW_ENGINE);*/
-
- /* Use SWI2C for dce8 currently, sicne we have bug with hwi2c */
- bool use_i2c_sw_engine = true;
-
- uint32_t i;
-
- dal_i2caux_construct(base, ctx);
-
- i2caux_dce80->base.funcs = &i2caux_funcs;
- i2caux_dce80->i2c_hw_buffer_in_use = false;
-
- /* Create I2C HW engines (HW + SW pairs)
- * for all lines which has assisted HW DDC
- * 'i' (loop counter) used as DDC/AUX engine_id */
-
- i = 0;
-
- do {
- enum gpio_ddc_line line_id = hw_ddc_lines[i];
-
- struct i2c_hw_engine_dce80_create_arg hw_arg;
-
- if (use_i2c_sw_engine) {
- struct i2c_sw_engine_dce80_create_arg sw_arg;
-
- sw_arg.engine_id = i;
- sw_arg.default_speed = base->default_i2c_sw_speed;
- sw_arg.ctx = ctx;
- base->i2c_sw_engines[line_id] =
- dal_i2c_sw_engine_dce80_create(&sw_arg);
- }
-
- hw_arg.engine_id = i;
- hw_arg.reference_frequency = reference_frequency;
- hw_arg.default_speed = base->default_i2c_hw_speed;
- hw_arg.ctx = ctx;
-
- base->i2c_hw_engines[line_id] =
- dal_i2c_hw_engine_dce80_create(&hw_arg);
-
- ++i;
- } while (i < ARRAY_SIZE(hw_ddc_lines));
-
- /* Create AUX engines for all lines which has assisted HW AUX
- * 'i' (loop counter) used as DDC/AUX engine_id */
-
- i = 0;
-
- do {
- enum gpio_ddc_line line_id = hw_aux_lines[i];
-
- struct aux_engine_dce110_init_data arg;
-
- arg.engine_id = i;
- arg.timeout_period = base->aux_timeout_period;
- arg.ctx = ctx;
- arg.regs = &dce80_aux_regs[i];
-
- base->aux_engines[line_id] =
- dal_aux_engine_dce110_create(&arg);
-
- ++i;
- } while (i < ARRAY_SIZE(hw_aux_lines));
-
- /* TODO Generic I2C SW and HW */
-}
-
-struct i2caux *dal_i2caux_dce80_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce80 *i2caux_dce80 =
- kzalloc(sizeof(struct i2caux_dce80), GFP_KERNEL);
-
- if (!i2caux_dce80) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- construct(i2caux_dce80, ctx);
- return &i2caux_dce80->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c
deleted file mode 100644
index a59c1f50c1e8..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-#include "../dce110/aux_engine_dce110.h"
-#include "../dce110/i2c_hw_engine_dce110.h"
-#include "../dce110/i2caux_dce110.h"
-
-#include "dcn/dcn_1_0_offset.h"
-#include "dcn/dcn_1_0_sh_mask.h"
-#include "soc15_hw_ip.h"
-#include "vega10_ip_offset.h"
-
-/* begin *********************
- * macros to expend register list macro defined in HW object header file */
-
-#define BASE_INNER(seg) \
- DCE_BASE__INST0_SEG ## seg
-
-/* compile time expand base address. */
-#define BASE(seg) \
- BASE_INNER(seg)
-
-#define SR(reg_name)\
- .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
- mm ## reg_name
-
-#define SRI(reg_name, block, id)\
- .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
- mm ## block ## id ## _ ## reg_name
-/* macros to expend register list macro defined in HW object header file
- * end *********************/
-
-#define aux_regs(id)\
-[id] = {\
- AUX_COMMON_REG_LIST(id), \
- .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK \
-}
-
-#define hw_engine_regs(id)\
-{\
- I2C_HW_ENGINE_COMMON_REG_LIST(id) \
-}
-
-static const struct dce110_aux_registers dcn10_aux_regs[] = {
- aux_regs(0),
- aux_regs(1),
- aux_regs(2),
- aux_regs(3),
- aux_regs(4),
- aux_regs(5),
-};
-
-static const struct dce110_i2c_hw_engine_registers dcn10_hw_engine_regs[] = {
- hw_engine_regs(1),
- hw_engine_regs(2),
- hw_engine_regs(3),
- hw_engine_regs(4),
- hw_engine_regs(5),
- hw_engine_regs(6)
-};
-
-static const struct dce110_i2c_hw_engine_shift i2c_shift = {
- I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT)
-};
-
-static const struct dce110_i2c_hw_engine_mask i2c_mask = {
- I2C_COMMON_MASK_SH_LIST_DCE110(_MASK)
-};
-
-struct i2caux *dal_i2caux_dcn10_create(
- struct dc_context *ctx)
-{
- struct i2caux_dce110 *i2caux_dce110 =
- kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL);
-
- if (!i2caux_dce110) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- dal_i2caux_dce110_construct(i2caux_dce110,
- ctx,
- ARRAY_SIZE(dcn10_aux_regs),
- dcn10_aux_regs,
- dcn10_hw_engine_regs,
- &i2c_shift,
- &i2c_mask);
- return &i2caux_dce110->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h
deleted file mode 100644
index aeb4a86463d4..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_AUX_DCN10_H__
-#define __DAL_I2C_AUX_DCN10_H__
-
-struct i2caux *dal_i2caux_dcn10_create(
- struct dc_context *ctx);
-
-#endif /* __DAL_I2C_AUX_DCN10_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c b/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c
deleted file mode 100644
index e6408f644086..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#include "dm_services.h"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "../i2caux.h"
-#include "../engine.h"
-#include "../i2c_engine.h"
-#include "../i2c_sw_engine.h"
-#include "../i2c_hw_engine.h"
-
-/*
- * Header of this unit
- */
-#include "i2caux_diag.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-static void destruct(
- struct i2caux *i2caux)
-{
- dal_i2caux_destruct(i2caux);
-}
-
-static void destroy(
- struct i2caux **i2c_engine)
-{
- destruct(*i2c_engine);
-
- kfree(*i2c_engine);
-
- *i2c_engine = NULL;
-}
-
-/* function table */
-static const struct i2caux_funcs i2caux_funcs = {
- .destroy = destroy,
- .acquire_i2c_hw_engine = NULL,
- .release_engine = NULL,
- .acquire_i2c_sw_engine = NULL,
- .acquire_aux_engine = NULL,
-};
-
-static void construct(
- struct i2caux *i2caux,
- struct dc_context *ctx)
-{
- dal_i2caux_construct(i2caux, ctx);
- i2caux->funcs = &i2caux_funcs;
-}
-
-struct i2caux *dal_i2caux_diag_fpga_create(
- struct dc_context *ctx)
-{
- struct i2caux *i2caux = kzalloc(sizeof(struct i2caux),
- GFP_KERNEL);
-
- if (!i2caux) {
- ASSERT_CRITICAL(false);
- return NULL;
- }
-
- construct(i2caux, ctx);
- return i2caux;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h b/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h
deleted file mode 100644
index a83eeb748283..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_AUX_DIAG_FPGA_H__
-#define __DAL_I2C_AUX_DIAG_FPGA_H__
-
-struct i2caux *dal_i2caux_diag_fpga_create(
- struct dc_context *ctx);
-
-#endif /* __DAL_I2C_AUX_DIAG_FPGA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h
deleted file mode 100644
index b16fb1ff687d..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_ENGINE_H__
-#define __DAL_ENGINE_H__
-
-#include "dc_ddc_types.h"
-
-enum i2caux_transaction_operation {
- I2CAUX_TRANSACTION_READ,
- I2CAUX_TRANSACTION_WRITE
-};
-
-enum i2caux_transaction_address_space {
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1,
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD
-};
-
-struct i2caux_transaction_payload {
- enum i2caux_transaction_address_space address_space;
- uint32_t address;
- uint32_t length;
- uint8_t *data;
-};
-
-enum i2caux_transaction_status {
- I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L),
- I2CAUX_TRANSACTION_STATUS_SUCCEEDED,
- I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY,
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT,
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR,
- I2CAUX_TRANSACTION_STATUS_FAILED_NACK,
- I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE,
- I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION,
- I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION,
- I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW,
- I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON
-};
-
-struct i2caux_transaction_request {
- enum i2caux_transaction_operation operation;
- struct i2caux_transaction_payload payload;
- enum i2caux_transaction_status status;
-};
-
-enum i2caux_engine_type {
- I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L),
- I2CAUX_ENGINE_TYPE_AUX,
- I2CAUX_ENGINE_TYPE_I2C_DDC_HW,
- I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW,
- I2CAUX_ENGINE_TYPE_I2C_SW
-};
-
-enum i2c_default_speed {
- I2CAUX_DEFAULT_I2C_HW_SPEED = 50,
- I2CAUX_DEFAULT_I2C_SW_SPEED = 50
-};
-
-struct engine;
-
-struct engine_funcs {
- enum i2caux_engine_type (*get_engine_type)(
- const struct engine *engine);
- bool (*acquire)(
- struct engine *engine,
- struct ddc *ddc);
- bool (*submit_request)(
- struct engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction);
- void (*release_engine)(
- struct engine *engine);
-};
-
-struct engine {
- const struct engine_funcs *funcs;
- uint32_t inst;
- struct ddc *ddc;
- struct dc_context *ctx;
-};
-
-void dal_i2caux_construct_engine(
- struct engine *engine,
- struct dc_context *ctx);
-
-void dal_i2caux_destruct_engine(
- struct engine *engine);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c
deleted file mode 100644
index 70e20bd47ce4..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_engine.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-#define FROM_ENGINE(ptr) \
- container_of((ptr), struct i2c_engine, base)
-
-bool dal_i2c_engine_acquire(
- struct engine *engine,
- struct ddc *ddc_handle)
-{
- struct i2c_engine *i2c_engine = FROM_ENGINE(engine);
-
- uint32_t counter = 0;
- bool result;
-
- do {
- result = i2c_engine->funcs->acquire_engine(
- i2c_engine, ddc_handle);
-
- if (result)
- break;
-
- /* i2c_engine is busy by VBios, lets wait and retry */
-
- udelay(10);
-
- ++counter;
- } while (counter < 2);
-
- if (result) {
- if (!i2c_engine->funcs->setup_engine(i2c_engine)) {
- engine->funcs->release_engine(engine);
- result = false;
- }
- }
-
- return result;
-}
-
-bool dal_i2c_engine_setup_i2c_engine(
- struct i2c_engine *engine)
-{
- /* Derivative classes do not have to override this */
-
- return true;
-}
-
-void dal_i2c_engine_submit_channel_request(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *request)
-{
-
-}
-
-void dal_i2c_engine_process_channel_reply(
- struct i2c_engine *engine,
- struct i2c_reply_transaction_data *reply)
-{
-
-}
-
-void dal_i2c_engine_construct(
- struct i2c_engine *engine,
- struct dc_context *ctx)
-{
- dal_i2caux_construct_engine(&engine->base, ctx);
- engine->timeout_delay = 0;
-}
-
-void dal_i2c_engine_destruct(
- struct i2c_engine *engine)
-{
- dal_i2caux_destruct_engine(&engine->base);
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h
deleted file mode 100644
index ded6ea34b714..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_ENGINE_H__
-#define __DAL_I2C_ENGINE_H__
-
-enum i2c_channel_operation_result {
- I2C_CHANNEL_OPERATION_SUCCEEDED,
- I2C_CHANNEL_OPERATION_FAILED,
- I2C_CHANNEL_OPERATION_NOT_GRANTED,
- I2C_CHANNEL_OPERATION_IS_BUSY,
- I2C_CHANNEL_OPERATION_NO_HANDLE_PROVIDED,
- I2C_CHANNEL_OPERATION_CHANNEL_IN_USE,
- I2C_CHANNEL_OPERATION_CHANNEL_CLIENT_MAX_ALLOWED,
- I2C_CHANNEL_OPERATION_ENGINE_BUSY,
- I2C_CHANNEL_OPERATION_TIMEOUT,
- I2C_CHANNEL_OPERATION_NO_RESPONSE,
- I2C_CHANNEL_OPERATION_HW_REQUEST_I2C_BUS,
- I2C_CHANNEL_OPERATION_WRONG_PARAMETER,
- I2C_CHANNEL_OPERATION_OUT_NB_OF_RETRIES,
- I2C_CHANNEL_OPERATION_NOT_STARTED
-};
-
-struct i2c_request_transaction_data {
- enum i2caux_transaction_action action;
- enum i2c_channel_operation_result status;
- uint8_t address;
- uint32_t length;
- uint8_t *data;
-};
-
-struct i2c_reply_transaction_data {
- uint32_t length;
- uint8_t *data;
-};
-
-struct i2c_engine;
-
-struct i2c_engine_funcs {
- void (*destroy)(
- struct i2c_engine **ptr);
- uint32_t (*get_speed)(
- const struct i2c_engine *engine);
- void (*set_speed)(
- struct i2c_engine *engine,
- uint32_t speed);
- bool (*acquire_engine)(
- struct i2c_engine *engine,
- struct ddc *ddc);
- bool (*setup_engine)(
- struct i2c_engine *engine);
- void (*submit_channel_request)(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *request);
- void (*process_channel_reply)(
- struct i2c_engine *engine,
- struct i2c_reply_transaction_data *reply);
- enum i2c_channel_operation_result (*get_channel_status)(
- struct i2c_engine *engine,
- uint8_t *returned_bytes);
-};
-
-struct i2c_engine {
- struct engine base;
- const struct i2c_engine_funcs *funcs;
- uint32_t timeout_delay;
- uint32_t setup_limit;
- uint32_t send_reset_length;
-};
-
-void dal_i2c_engine_construct(
- struct i2c_engine *engine,
- struct dc_context *ctx);
-
-void dal_i2c_engine_destruct(
- struct i2c_engine *engine);
-
-bool dal_i2c_engine_setup_i2c_engine(
- struct i2c_engine *engine);
-
-void dal_i2c_engine_submit_channel_request(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *request);
-
-void dal_i2c_engine_process_channel_reply(
- struct i2c_engine *engine,
- struct i2c_reply_transaction_data *reply);
-
-bool dal_i2c_engine_acquire(
- struct engine *ptr,
- struct ddc *ddc_handle);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c
deleted file mode 100644
index 5a4295e0fae5..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "engine.h"
-#include "i2c_engine.h"
-#include "i2c_hw_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_generic_hw_engine.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-/*
- * @brief
- * Cast 'struct i2c_hw_engine *'
- * to 'struct i2c_generic_hw_engine *'
- */
-#define FROM_I2C_HW_ENGINE(ptr) \
- container_of((ptr), struct i2c_generic_hw_engine, base)
-
-/*
- * @brief
- * Cast 'struct i2c_engine *'
- * to 'struct i2c_generic_hw_engine *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base))
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct i2c_generic_hw_engine *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type(
- const struct engine *engine)
-{
- return I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW;
-}
-
-/*
- * @brief
- * Single transaction handling.
- * Since transaction may be bigger than HW buffer size,
- * it divides transaction to sub-transactions
- * and uses batch transaction feature of the engine.
- */
-bool dal_i2c_generic_hw_engine_submit_request(
- struct engine *engine,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction)
-{
- struct i2c_generic_hw_engine *hw_engine = FROM_ENGINE(engine);
-
- struct i2c_hw_engine *base = &hw_engine->base;
-
- uint32_t max_payload_size =
- base->funcs->get_hw_buffer_available_size(base);
-
- bool initial_stop_bit = !middle_of_transaction;
-
- struct i2c_generic_transaction_attributes attributes;
-
- enum i2c_channel_operation_result operation_result =
- I2C_CHANNEL_OPERATION_FAILED;
-
- bool result = false;
-
- /* setup transaction initial properties */
-
- uint8_t address = i2caux_request->payload.address;
- uint8_t *current_payload = i2caux_request->payload.data;
- uint32_t remaining_payload_size = i2caux_request->payload.length;
-
- bool first_iteration = true;
-
- if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
- attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_READ;
- else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
- attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- else {
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
- return false;
- }
-
- /* Do batch transaction.
- * Divide read/write data into payloads which fit HW buffer size.
- * 1. Single transaction:
- * start_bit = 1, stop_bit depends on session state, ack_on_read = 0;
- * 2. Start of batch transaction:
- * start_bit = 1, stop_bit = 0, ack_on_read = 1;
- * 3. Middle of batch transaction:
- * start_bit = 0, stop_bit = 0, ack_on_read = 1;
- * 4. End of batch transaction:
- * start_bit = 0, stop_bit depends on session state, ack_on_read = 0.
- * Session stop bit is set if 'middle_of_transaction' = 0. */
-
- while (remaining_payload_size) {
- uint32_t current_transaction_size;
- uint32_t current_payload_size;
-
- bool last_iteration;
- bool stop_bit;
-
- /* Calculate current transaction size and payload size.
- * Transaction size = total number of bytes in transaction,
- * including slave's address;
- * Payload size = number of data bytes in transaction. */
-
- if (first_iteration) {
- /* In the first sub-transaction we send slave's address
- * thus we need to reserve one byte for it */
- current_transaction_size =
- (remaining_payload_size > max_payload_size - 1) ?
- max_payload_size :
- remaining_payload_size + 1;
-
- current_payload_size = current_transaction_size - 1;
- } else {
- /* Second and further sub-transactions will have
- * entire buffer reserved for data */
- current_transaction_size =
- (remaining_payload_size > max_payload_size) ?
- max_payload_size :
- remaining_payload_size;
-
- current_payload_size = current_transaction_size;
- }
-
- last_iteration =
- (remaining_payload_size == current_payload_size);
-
- stop_bit = last_iteration ? initial_stop_bit : false;
-
- /* write slave device address */
-
- if (first_iteration)
- hw_engine->funcs->write_address(hw_engine, address);
-
- /* write current portion of data, if requested */
-
- if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
- hw_engine->funcs->write_data(
- hw_engine,
- current_payload,
- current_payload_size);
-
- /* execute transaction */
-
- attributes.start_bit = first_iteration;
- attributes.stop_bit = stop_bit;
- attributes.last_read = last_iteration;
- attributes.transaction_size = current_transaction_size;
-
- hw_engine->funcs->execute_transaction(hw_engine, &attributes);
-
- /* wait until transaction is processed; if it fails - quit */
-
- operation_result = base->funcs->wait_on_operation_result(
- base,
- base->funcs->get_transaction_timeout(
- base, current_transaction_size),
- I2C_CHANNEL_OPERATION_ENGINE_BUSY);
-
- if (operation_result != I2C_CHANNEL_OPERATION_SUCCEEDED)
- break;
-
- /* read current portion of data, if requested */
-
- /* the read offset should be 1 for first sub-transaction,
- * and 0 for any next one */
-
- if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
- hw_engine->funcs->read_data(hw_engine, current_payload,
- current_payload_size, first_iteration ? 1 : 0);
-
- /* update loop variables */
-
- first_iteration = false;
- current_payload += current_payload_size;
- remaining_payload_size -= current_payload_size;
- }
-
- /* update transaction status */
-
- switch (operation_result) {
- case I2C_CHANNEL_OPERATION_SUCCEEDED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- result = true;
- break;
- case I2C_CHANNEL_OPERATION_NO_RESPONSE:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- break;
- case I2C_CHANNEL_OPERATION_TIMEOUT:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- break;
- case I2C_CHANNEL_OPERATION_FAILED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
- break;
- default:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
- }
-
- return result;
-}
-
-/*
- * @brief
- * Returns number of microseconds to wait until timeout to be considered
- */
-uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout(
- const struct i2c_hw_engine *engine,
- uint32_t length)
-{
- const struct i2c_engine *base = &engine->base;
-
- uint32_t speed = base->funcs->get_speed(base);
-
- if (!speed)
- return 0;
-
- /* total timeout = period_timeout * (start + data bits count + stop) */
-
- return ((1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed) *
- (1 + (length << 3) + 1);
-}
-
-void dal_i2c_generic_hw_engine_construct(
- struct i2c_generic_hw_engine *engine,
- struct dc_context *ctx)
-{
- dal_i2c_hw_engine_construct(&engine->base, ctx);
-}
-
-void dal_i2c_generic_hw_engine_destruct(
- struct i2c_generic_hw_engine *engine)
-{
- dal_i2c_hw_engine_destruct(&engine->base);
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h
deleted file mode 100644
index 1da0397b04a2..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_GENERIC_HW_ENGINE_H__
-#define __DAL_I2C_GENERIC_HW_ENGINE_H__
-
-struct i2c_generic_transaction_attributes {
- enum i2caux_transaction_action action;
- uint32_t transaction_size;
- bool start_bit;
- bool stop_bit;
- bool last_read;
-};
-
-struct i2c_generic_hw_engine;
-
-struct i2c_generic_hw_engine_funcs {
- void (*write_address)(
- struct i2c_generic_hw_engine *engine,
- uint8_t address);
- void (*write_data)(
- struct i2c_generic_hw_engine *engine,
- const uint8_t *buffer,
- uint32_t length);
- void (*read_data)(
- struct i2c_generic_hw_engine *engine,
- uint8_t *buffer,
- uint32_t length,
- uint32_t offset);
- void (*execute_transaction)(
- struct i2c_generic_hw_engine *engine,
- struct i2c_generic_transaction_attributes *attributes);
-};
-
-struct i2c_generic_hw_engine {
- struct i2c_hw_engine base;
- const struct i2c_generic_hw_engine_funcs *funcs;
-};
-
-void dal_i2c_generic_hw_engine_construct(
- struct i2c_generic_hw_engine *engine,
- struct dc_context *ctx);
-
-void dal_i2c_generic_hw_engine_destruct(
- struct i2c_generic_hw_engine *engine);
-enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type(
- const struct engine *engine);
-bool dal_i2c_generic_hw_engine_submit_request(
- struct engine *ptr,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction);
-uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout(
- const struct i2c_hw_engine *engine,
- uint32_t length);
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c
deleted file mode 100644
index 141898533e8e..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dm_event_log.h"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "engine.h"
-#include "i2c_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_hw_engine.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-/*
- * @brief
- * Cast 'struct i2c_engine *'
- * to 'struct i2c_hw_engine *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- container_of((ptr), struct i2c_hw_engine, base)
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct i2c_hw_engine *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
- const struct engine *engine)
-{
- return I2CAUX_ENGINE_TYPE_I2C_DDC_HW;
-}
-
-bool dal_i2c_hw_engine_submit_request(
- struct engine *engine,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction)
-{
- struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine);
-
- struct i2c_request_transaction_data request;
-
- uint32_t transaction_timeout;
-
- enum i2c_channel_operation_result operation_result;
-
- bool result = false;
-
- /* We need following:
- * transaction length will not exceed
- * the number of free bytes in HW buffer (minus one for address)*/
-
- if (i2caux_request->payload.length >=
- hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) {
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW;
- return false;
- }
-
- if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
- request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_READ;
- else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
- request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- else {
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
- /* [anaumov] in DAL2, there was no "return false" */
- return false;
- }
-
- request.address = (uint8_t)i2caux_request->payload.address;
- request.length = i2caux_request->payload.length;
- request.data = i2caux_request->payload.data;
-
- /* obtain timeout value before submitting request */
-
- transaction_timeout = hw_engine->funcs->get_transaction_timeout(
- hw_engine, i2caux_request->payload.length + 1);
-
- hw_engine->base.funcs->submit_channel_request(
- &hw_engine->base, &request);
- /* EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_I2C, */
- /* request.action, request.address, request.length, request.data); */
-
- if ((request.status == I2C_CHANNEL_OPERATION_FAILED) ||
- (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) {
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
- return false;
- }
-
- /* wait until transaction proceed */
-
- operation_result = hw_engine->funcs->wait_on_operation_result(
- hw_engine,
- transaction_timeout,
- I2C_CHANNEL_OPERATION_ENGINE_BUSY);
-
- /* update transaction status */
-
- switch (operation_result) {
- case I2C_CHANNEL_OPERATION_SUCCEEDED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- result = true;
- break;
- case I2C_CHANNEL_OPERATION_NO_RESPONSE:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- break;
- case I2C_CHANNEL_OPERATION_TIMEOUT:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- break;
- case I2C_CHANNEL_OPERATION_FAILED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
- break;
- default:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
- }
-
- if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) {
- struct i2c_reply_transaction_data reply;
-
- reply.data = i2caux_request->payload.data;
- reply.length = i2caux_request->payload.length;
-
- hw_engine->base.funcs->
- process_channel_reply(&hw_engine->base, &reply);
- /* EVENT_LOG_AUX_REP(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_I2C, */
- /* AUX_TRANSACTION_REPLY_I2C_ACK, reply.length, reply.data); */
- }
-
-
-
- return result;
-}
-
-bool dal_i2c_hw_engine_acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc)
-{
- enum gpio_result result;
- uint32_t current_speed;
-
- result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
- GPIO_DDC_CONFIG_TYPE_MODE_I2C);
-
- if (result != GPIO_RESULT_OK)
- return false;
-
- engine->base.ddc = ddc;
-
- current_speed = engine->funcs->get_speed(engine);
-
- if (current_speed)
- FROM_I2C_ENGINE(engine)->original_speed = current_speed;
-
- return true;
-}
-/*
- * @brief
- * Queries in a loop for current engine status
- * until retrieved status matches 'expected_result', or timeout occurs.
- * Timeout given in microseconds
- * and the status query frequency is also one per microsecond.
- */
-enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
- struct i2c_hw_engine *engine,
- uint32_t timeout,
- enum i2c_channel_operation_result expected_result)
-{
- enum i2c_channel_operation_result result;
- uint32_t i = 0;
-
- if (!timeout)
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-
- do {
- result = engine->base.funcs->get_channel_status(
- &engine->base, NULL);
-
- if (result != expected_result)
- break;
-
- udelay(1);
-
- ++i;
- } while (i < timeout);
-
- return result;
-}
-
-void dal_i2c_hw_engine_construct(
- struct i2c_hw_engine *engine,
- struct dc_context *ctx)
-{
- dal_i2c_engine_construct(&engine->base, ctx);
- engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
- engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
-}
-
-void dal_i2c_hw_engine_destruct(
- struct i2c_hw_engine *engine)
-{
- dal_i2c_engine_destruct(&engine->base);
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h
deleted file mode 100644
index 8936a994804a..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_HW_ENGINE_H__
-#define __DAL_I2C_HW_ENGINE_H__
-
-enum {
- TRANSACTION_TIMEOUT_IN_I2C_CLOCKS = 32
-};
-
-struct i2c_hw_engine;
-
-struct i2c_hw_engine_funcs {
- uint32_t (*get_hw_buffer_available_size)(
- const struct i2c_hw_engine *engine);
- enum i2c_channel_operation_result (*wait_on_operation_result)(
- struct i2c_hw_engine *engine,
- uint32_t timeout,
- enum i2c_channel_operation_result expected_result);
- uint32_t (*get_transaction_timeout)(
- const struct i2c_hw_engine *engine,
- uint32_t length);
-};
-
-struct i2c_hw_engine {
- struct i2c_engine base;
- const struct i2c_hw_engine_funcs *funcs;
-
- /* Values below are in kilohertz */
- uint32_t original_speed;
- uint32_t default_speed;
-};
-
-void dal_i2c_hw_engine_construct(
- struct i2c_hw_engine *engine,
- struct dc_context *ctx);
-
-void dal_i2c_hw_engine_destruct(
- struct i2c_hw_engine *engine);
-
-enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
- struct i2c_hw_engine *engine,
- uint32_t timeout,
- enum i2c_channel_operation_result expected_result);
-
-bool dal_i2c_hw_engine_acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc);
-
-bool dal_i2c_hw_engine_submit_request(
- struct engine *ptr,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction);
-
-enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
- const struct engine *engine);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c
deleted file mode 100644
index 8e19bb629394..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "engine.h"
-#include "i2c_engine.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2c_sw_engine.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-/*
- * This unit
- */
-
-#define SCL false
-#define SDA true
-
-static inline bool read_bit_from_ddc(
- struct ddc *ddc,
- bool data_nor_clock)
-{
- uint32_t value = 0;
-
- if (data_nor_clock)
- dal_gpio_get_value(ddc->pin_data, &value);
- else
- dal_gpio_get_value(ddc->pin_clock, &value);
-
- return (value != 0);
-}
-
-static inline void write_bit_to_ddc(
- struct ddc *ddc,
- bool data_nor_clock,
- bool bit)
-{
- uint32_t value = bit ? 1 : 0;
-
- if (data_nor_clock)
- dal_gpio_set_value(ddc->pin_data, value);
- else
- dal_gpio_set_value(ddc->pin_clock, value);
-}
-
-static bool wait_for_scl_high(
- struct dc_context *ctx,
- struct ddc *ddc,
- uint16_t clock_delay_div_4)
-{
- uint32_t scl_retry = 0;
- uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4;
-
- udelay(clock_delay_div_4);
-
- /* 3 milliseconds delay
- * to wake up some displays from "low power" state.
- */
-
- do {
- if (read_bit_from_ddc(ddc, SCL))
- return true;
-
- udelay(clock_delay_div_4);
-
- ++scl_retry;
- } while (scl_retry <= scl_retry_max);
-
- return false;
-}
-
-static bool start_sync(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4)
-{
- uint32_t retry = 0;
-
- /* The I2C communications start signal is:
- * the SDA going low from high, while the SCL is high. */
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- udelay(clock_delay_div_4);
-
- do {
- write_bit_to_ddc(ddc_handle, SDA, true);
-
- if (!read_bit_from_ddc(ddc_handle, SDA)) {
- ++retry;
- continue;
- }
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- break;
-
- write_bit_to_ddc(ddc_handle, SDA, false);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- udelay(clock_delay_div_4);
-
- return true;
- } while (retry <= I2C_SW_RETRIES);
-
- return false;
-}
-
-static bool stop_sync(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4)
-{
- uint32_t retry = 0;
-
- /* The I2C communications stop signal is:
- * the SDA going high from low, while the SCL is high. */
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SDA, false);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- return false;
-
- write_bit_to_ddc(ddc_handle, SDA, true);
-
- do {
- udelay(clock_delay_div_4);
-
- if (read_bit_from_ddc(ddc_handle, SDA))
- return true;
-
- ++retry;
- } while (retry <= 2);
-
- return false;
-}
-
-static bool write_byte(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4,
- uint8_t byte)
-{
- int32_t shift = 7;
- bool ack;
-
- /* bits are transmitted serially, starting from MSB */
-
- do {
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SDA, (byte >> shift) & 1);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- return false;
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- --shift;
- } while (shift >= 0);
-
- /* The display sends ACK by preventing the SDA from going high
- * after the SCL pulse we use to send our last data bit.
- * If the SDA goes high after that bit, it's a NACK */
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SDA, true);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- return false;
-
- /* read ACK bit */
-
- ack = !read_bit_from_ddc(ddc_handle, SDA);
-
- udelay(clock_delay_div_4 << 1);
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- udelay(clock_delay_div_4 << 1);
-
- return ack;
-}
-
-static bool read_byte(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4,
- uint8_t *byte,
- bool more)
-{
- int32_t shift = 7;
-
- uint8_t data = 0;
-
- /* The data bits are read from MSB to LSB;
- * bit is read while SCL is high */
-
- do {
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- return false;
-
- if (read_bit_from_ddc(ddc_handle, SDA))
- data |= (1 << shift);
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- udelay(clock_delay_div_4 << 1);
-
- --shift;
- } while (shift >= 0);
-
- /* read only whole byte */
-
- *byte = data;
-
- udelay(clock_delay_div_4);
-
- /* send the acknowledge bit:
- * SDA low means ACK, SDA high means NACK */
-
- write_bit_to_ddc(ddc_handle, SDA, !more);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SCL, true);
-
- if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
- return false;
-
- write_bit_to_ddc(ddc_handle, SCL, false);
-
- udelay(clock_delay_div_4);
-
- write_bit_to_ddc(ddc_handle, SDA, true);
-
- udelay(clock_delay_div_4);
-
- return true;
-}
-
-static bool i2c_write(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4,
- uint8_t address,
- uint32_t length,
- const uint8_t *data)
-{
- uint32_t i = 0;
-
- if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address))
- return false;
-
- while (i < length) {
- if (!write_byte(ctx, ddc_handle, clock_delay_div_4, data[i]))
- return false;
- ++i;
- }
-
- return true;
-}
-
-static bool i2c_read(
- struct dc_context *ctx,
- struct ddc *ddc_handle,
- uint16_t clock_delay_div_4,
- uint8_t address,
- uint32_t length,
- uint8_t *data)
-{
- uint32_t i = 0;
-
- if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address))
- return false;
-
- while (i < length) {
- if (!read_byte(ctx, ddc_handle, clock_delay_div_4, data + i,
- i < length - 1))
- return false;
- ++i;
- }
-
- return true;
-}
-
-/*
- * @brief
- * Cast 'struct i2c_engine *'
- * to 'struct i2c_sw_engine *'
- */
-#define FROM_I2C_ENGINE(ptr) \
- container_of((ptr), struct i2c_sw_engine, base)
-
-/*
- * @brief
- * Cast 'struct engine *'
- * to 'struct i2c_sw_engine *'
- */
-#define FROM_ENGINE(ptr) \
- FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
-
-enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type(
- const struct engine *engine)
-{
- return I2CAUX_ENGINE_TYPE_I2C_SW;
-}
-
-bool dal_i2c_sw_engine_submit_request(
- struct engine *engine,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction)
-{
- struct i2c_sw_engine *sw_engine = FROM_ENGINE(engine);
-
- struct i2c_engine *base = &sw_engine->base;
-
- struct i2c_request_transaction_data request;
- bool operation_succeeded = false;
-
- if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
- request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_READ;
- else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
- request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- else {
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
- /* in DAL2, there was no "return false" */
- return false;
- }
-
- request.address = (uint8_t)i2caux_request->payload.address;
- request.length = i2caux_request->payload.length;
- request.data = i2caux_request->payload.data;
-
- base->funcs->submit_channel_request(base, &request);
-
- if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) ||
- (request.status == I2C_CHANNEL_OPERATION_FAILED))
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
- else {
- enum i2c_channel_operation_result operation_result;
-
- do {
- operation_result =
- base->funcs->get_channel_status(base, NULL);
-
- switch (operation_result) {
- case I2C_CHANNEL_OPERATION_SUCCEEDED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- operation_succeeded = true;
- break;
- case I2C_CHANNEL_OPERATION_NO_RESPONSE:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- break;
- case I2C_CHANNEL_OPERATION_TIMEOUT:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- break;
- case I2C_CHANNEL_OPERATION_FAILED:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
- break;
- default:
- i2caux_request->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
- break;
- }
- } while (operation_result == I2C_CHANNEL_OPERATION_ENGINE_BUSY);
- }
-
- return operation_succeeded;
-}
-
-uint32_t dal_i2c_sw_engine_get_speed(
- const struct i2c_engine *engine)
-{
- return FROM_I2C_ENGINE(engine)->speed;
-}
-
-void dal_i2c_sw_engine_set_speed(
- struct i2c_engine *engine,
- uint32_t speed)
-{
- struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine);
-
- ASSERT(speed);
-
- sw_engine->speed = speed ? speed : I2CAUX_DEFAULT_I2C_SW_SPEED;
-
- sw_engine->clock_delay = 1000 / sw_engine->speed;
-
- if (sw_engine->clock_delay < 12)
- sw_engine->clock_delay = 12;
-}
-
-bool dal_i2caux_i2c_sw_engine_acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc)
-{
- enum gpio_result result;
-
- result = dal_ddc_open(ddc, GPIO_MODE_FAST_OUTPUT,
- GPIO_DDC_CONFIG_TYPE_MODE_I2C);
-
- if (result != GPIO_RESULT_OK)
- return false;
-
- engine->base.ddc = ddc;
-
- return true;
-}
-
-void dal_i2c_sw_engine_submit_channel_request(
- struct i2c_engine *engine,
- struct i2c_request_transaction_data *req)
-{
- struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine);
-
- struct ddc *ddc = engine->base.ddc;
- uint16_t clock_delay_div_4 = sw_engine->clock_delay >> 2;
-
- /* send sync (start / repeated start) */
-
- bool result = start_sync(engine->base.ctx, ddc, clock_delay_div_4);
-
- /* process payload */
-
- if (result) {
- switch (req->action) {
- case I2CAUX_TRANSACTION_ACTION_I2C_WRITE:
- case I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT:
- result = i2c_write(engine->base.ctx, ddc, clock_delay_div_4,
- req->address, req->length, req->data);
- break;
- case I2CAUX_TRANSACTION_ACTION_I2C_READ:
- case I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT:
- result = i2c_read(engine->base.ctx, ddc, clock_delay_div_4,
- req->address, req->length, req->data);
- break;
- default:
- result = false;
- break;
- }
- }
-
- /* send stop if not 'mot' or operation failed */
-
- if (!result ||
- (req->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
- (req->action == I2CAUX_TRANSACTION_ACTION_I2C_READ))
- if (!stop_sync(engine->base.ctx, ddc, clock_delay_div_4))
- result = false;
-
- req->status = result ?
- I2C_CHANNEL_OPERATION_SUCCEEDED :
- I2C_CHANNEL_OPERATION_FAILED;
-}
-
-enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status(
- struct i2c_engine *engine,
- uint8_t *returned_bytes)
-{
- /* No arbitration with VBIOS is performed since DCE 6.0 */
- return I2C_CHANNEL_OPERATION_SUCCEEDED;
-}
-
-void dal_i2c_sw_engine_destruct(
- struct i2c_sw_engine *engine)
-{
- dal_i2c_engine_destruct(&engine->base);
-}
-
-static void destroy(
- struct i2c_engine **ptr)
-{
- dal_i2c_sw_engine_destruct(FROM_I2C_ENGINE(*ptr));
-
- kfree(*ptr);
- *ptr = NULL;
-}
-
-static const struct i2c_engine_funcs i2c_engine_funcs = {
- .acquire_engine = dal_i2caux_i2c_sw_engine_acquire_engine,
- .destroy = destroy,
- .get_speed = dal_i2c_sw_engine_get_speed,
- .set_speed = dal_i2c_sw_engine_set_speed,
- .setup_engine = dal_i2c_engine_setup_i2c_engine,
- .submit_channel_request = dal_i2c_sw_engine_submit_channel_request,
- .process_channel_reply = dal_i2c_engine_process_channel_reply,
- .get_channel_status = dal_i2c_sw_engine_get_channel_status,
-};
-
-static void release_engine(
- struct engine *engine)
-{
-
-}
-
-static const struct engine_funcs engine_funcs = {
- .release_engine = release_engine,
- .get_engine_type = dal_i2c_sw_engine_get_engine_type,
- .acquire = dal_i2c_engine_acquire,
- .submit_request = dal_i2c_sw_engine_submit_request,
-};
-
-void dal_i2c_sw_engine_construct(
- struct i2c_sw_engine *engine,
- const struct i2c_sw_engine_create_arg *arg)
-{
- dal_i2c_engine_construct(&engine->base, arg->ctx);
- dal_i2c_sw_engine_set_speed(&engine->base, arg->default_speed);
- engine->base.funcs = &i2c_engine_funcs;
- engine->base.base.funcs = &engine_funcs;
-}
-
-struct i2c_engine *dal_i2c_sw_engine_create(
- const struct i2c_sw_engine_create_arg *arg)
-{
- struct i2c_sw_engine *engine;
-
- if (!arg) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- engine = kzalloc(sizeof(struct i2c_sw_engine), GFP_KERNEL);
-
- if (!engine) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- dal_i2c_sw_engine_construct(engine, arg);
- return &engine->base;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h
deleted file mode 100644
index 546f15b0d3f1..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_SW_ENGINE_H__
-#define __DAL_I2C_SW_ENGINE_H__
-
-enum {
- I2C_SW_RETRIES = 10,
- I2C_SW_SCL_READ_RETRIES = 128,
- /* following value is in microseconds */
- I2C_SW_TIMEOUT_DELAY = 3000
-};
-
-struct i2c_sw_engine;
-
-struct i2c_sw_engine {
- struct i2c_engine base;
- uint32_t clock_delay;
- /* Values below are in KHz */
- uint32_t speed;
- uint32_t default_speed;
-};
-
-struct i2c_sw_engine_create_arg {
- uint32_t default_speed;
- struct dc_context *ctx;
-};
-
-void dal_i2c_sw_engine_construct(
- struct i2c_sw_engine *engine,
- const struct i2c_sw_engine_create_arg *arg);
-
-bool dal_i2caux_i2c_sw_engine_acquire_engine(
- struct i2c_engine *engine,
- struct ddc *ddc_handle);
-
-void dal_i2c_sw_engine_destruct(
- struct i2c_sw_engine *engine);
-
-struct i2c_engine *dal_i2c_sw_engine_create(
- const struct i2c_sw_engine_create_arg *arg);
-enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type(
- const struct engine *engine);
-bool dal_i2c_sw_engine_submit_request(
- struct engine *ptr,
- struct i2caux_transaction_request *i2caux_request,
- bool middle_of_transaction);
-uint32_t dal_i2c_sw_engine_get_speed(
- const struct i2c_engine *engine);
-void dal_i2c_sw_engine_set_speed(
- struct i2c_engine *ptr,
- uint32_t speed);
-void dal_i2c_sw_engine_submit_channel_request(
- struct i2c_engine *ptr,
- struct i2c_request_transaction_data *req);
-enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status(
- struct i2c_engine *engine,
- uint8_t *returned_bytes);
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
deleted file mode 100644
index 1ad6e49102ff..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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"
-
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-#include "dc_bios_types.h"
-
-/*
- * Header of this unit
- */
-
-#include "i2caux.h"
-
-/*
- * Post-requisites: headers required by this unit
- */
-
-#include "engine.h"
-#include "i2c_engine.h"
-#include "aux_engine.h"
-
-/*
- * This unit
- */
-
-#include "dce80/i2caux_dce80.h"
-
-#include "dce100/i2caux_dce100.h"
-
-#include "dce110/i2caux_dce110.h"
-
-#include "dce112/i2caux_dce112.h"
-
-#include "dce120/i2caux_dce120.h"
-
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-#include "dcn10/i2caux_dcn10.h"
-#endif
-
-#include "diagnostics/i2caux_diag.h"
-
-/*
- * @brief
- * Plain API, available publicly
- */
-
-struct i2caux *dal_i2caux_create(
- struct dc_context *ctx)
-{
- if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
- return dal_i2caux_diag_fpga_create(ctx);
- }
-
- switch (ctx->dce_version) {
- case DCE_VERSION_8_0:
- case DCE_VERSION_8_1:
- case DCE_VERSION_8_3:
- return dal_i2caux_dce80_create(ctx);
- case DCE_VERSION_11_2:
- case DCE_VERSION_11_22:
- return dal_i2caux_dce112_create(ctx);
- case DCE_VERSION_11_0:
- return dal_i2caux_dce110_create(ctx);
- case DCE_VERSION_10_0:
- return dal_i2caux_dce100_create(ctx);
- case DCE_VERSION_12_0:
- case DCE_VERSION_12_1:
- return dal_i2caux_dce120_create(ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
- case DCN_VERSION_1_0:
- return dal_i2caux_dcn10_create(ctx);
-#endif
-
-#if defined(CONFIG_DRM_AMD_DC_DCN1_01)
- case DCN_VERSION_1_01:
- return dal_i2caux_dcn10_create(ctx);
-#endif
- default:
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-}
-
-bool dal_i2caux_submit_i2c_command(
- struct i2caux *i2caux,
- struct ddc *ddc,
- struct i2c_command *cmd)
-{
- struct i2c_engine *engine;
- uint8_t index_of_payload = 0;
- bool result;
-
- if (!ddc) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- if (!cmd) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- /*
- * default will be SW, however there is a feature flag in adapter
- * service that determines whether SW i2c_engine will be available or
- * not, if sw i2c is not available we will fallback to hw. This feature
- * flag is set to not creating sw i2c engine for every dce except dce80
- * currently
- */
- switch (cmd->engine) {
- case I2C_COMMAND_ENGINE_DEFAULT:
- case I2C_COMMAND_ENGINE_SW:
- /* try to acquire SW engine first,
- * acquire HW engine if SW engine not available */
- engine = i2caux->funcs->acquire_i2c_sw_engine(i2caux, ddc);
-
- if (!engine)
- engine = i2caux->funcs->acquire_i2c_hw_engine(
- i2caux, ddc);
- break;
- case I2C_COMMAND_ENGINE_HW:
- default:
- /* try to acquire HW engine first,
- * acquire SW engine if HW engine not available */
- engine = i2caux->funcs->acquire_i2c_hw_engine(i2caux, ddc);
-
- if (!engine)
- engine = i2caux->funcs->acquire_i2c_sw_engine(
- i2caux, ddc);
- }
-
- if (!engine)
- return false;
-
- engine->funcs->set_speed(engine, cmd->speed);
-
- result = true;
-
- while (index_of_payload < cmd->number_of_payloads) {
- bool mot = (index_of_payload != cmd->number_of_payloads - 1);
-
- struct i2c_payload *payload = cmd->payloads + index_of_payload;
-
- struct i2caux_transaction_request request = { 0 };
-
- request.operation = payload->write ?
- I2CAUX_TRANSACTION_WRITE :
- I2CAUX_TRANSACTION_READ;
-
- request.payload.address_space =
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
- request.payload.address = (payload->address << 1) |
- !payload->write;
- request.payload.length = payload->length;
- request.payload.data = payload->data;
-
- if (!engine->base.funcs->submit_request(
- &engine->base, &request, mot)) {
- result = false;
- break;
- }
-
- ++index_of_payload;
- }
-
- i2caux->funcs->release_engine(i2caux, &engine->base);
-
- return result;
-}
-
-bool dal_i2caux_submit_aux_command(
- struct i2caux *i2caux,
- struct ddc *ddc,
- struct aux_command *cmd)
-{
- struct aux_engine *engine;
- uint8_t index_of_payload = 0;
- bool result;
- bool mot;
-
- if (!ddc) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- if (!cmd) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc);
-
- if (!engine)
- return false;
-
- engine->delay = cmd->defer_delay;
- engine->max_defer_write_retry = cmd->max_defer_write_retry;
-
- result = true;
-
- while (index_of_payload < cmd->number_of_payloads) {
- struct aux_payload *payload = cmd->payloads + index_of_payload;
- struct i2caux_transaction_request request = { 0 };
-
- if (cmd->mot == I2C_MOT_UNDEF)
- mot = (index_of_payload != cmd->number_of_payloads - 1);
- else
- mot = (cmd->mot == I2C_MOT_TRUE);
-
- request.operation = payload->write ?
- I2CAUX_TRANSACTION_WRITE :
- I2CAUX_TRANSACTION_READ;
-
- if (payload->i2c_over_aux) {
- request.payload.address_space =
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
-
- request.payload.address = (payload->address << 1) |
- !payload->write;
- } else {
- request.payload.address_space =
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD;
-
- request.payload.address = payload->address;
- }
-
- request.payload.length = payload->length;
- request.payload.data = payload->data;
-
- if (!engine->base.funcs->submit_request(
- &engine->base, &request, mot)) {
- result = false;
- break;
- }
-
- ++index_of_payload;
- }
-
- i2caux->funcs->release_engine(i2caux, &engine->base);
-
- return result;
-}
-
-static bool get_hw_supported_ddc_line(
- struct ddc *ddc,
- enum gpio_ddc_line *line)
-{
- enum gpio_ddc_line line_found;
-
- *line = GPIO_DDC_LINE_UNKNOWN;
-
- if (!ddc) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- if (!ddc->hw_info.hw_supported)
- return false;
-
- line_found = dal_ddc_get_line(ddc);
-
- if (line_found >= GPIO_DDC_LINE_COUNT)
- return false;
-
- *line = line_found;
-
- return true;
-}
-
-void dal_i2caux_configure_aux(
- struct i2caux *i2caux,
- struct ddc *ddc,
- union aux_config cfg)
-{
- struct aux_engine *engine =
- i2caux->funcs->acquire_aux_engine(i2caux, ddc);
-
- if (!engine)
- return;
-
- engine->funcs->configure(engine, cfg);
-
- i2caux->funcs->release_engine(i2caux, &engine->base);
-}
-
-void dal_i2caux_destroy(
- struct i2caux **i2caux)
-{
- if (!i2caux || !*i2caux) {
- BREAK_TO_DEBUGGER();
- return;
- }
-
- (*i2caux)->funcs->destroy(i2caux);
-
- *i2caux = NULL;
-}
-
-/*
- * @brief
- * An utility function used by 'struct i2caux' and its descendants
- */
-
-uint32_t dal_i2caux_get_reference_clock(
- struct dc_bios *bios)
-{
- struct dc_firmware_info info = { { 0 } };
-
- if (bios->funcs->get_firmware_info(bios, &info) != BP_RESULT_OK)
- return 0;
-
- return info.pll_info.crystal_frequency;
-}
-
-/*
- * @brief
- * i2caux
- */
-
-enum {
- /* following are expressed in KHz */
- DEFAULT_I2C_SW_SPEED = 50,
- DEFAULT_I2C_HW_SPEED = 50,
-
- DEFAULT_I2C_SW_SPEED_100KHZ = 100,
- DEFAULT_I2C_HW_SPEED_100KHZ = 100,
-
- /* This is the timeout as defined in DP 1.2a,
- * 2.3.4 "Detailed uPacket TX AUX CH State Description". */
- AUX_TIMEOUT_PERIOD = 400,
-
- /* Ideally, the SW timeout should be just above 550usec
- * which is programmed in HW.
- * But the SW timeout of 600usec is not reliable,
- * because on some systems, delay_in_microseconds()
- * returns faster than it should.
- * EPR #379763: by trial-and-error on different systems,
- * 700usec is the minimum reliable SW timeout for polling
- * the AUX_SW_STATUS.AUX_SW_DONE bit.
- * This timeout expires *only* when there is
- * AUX Error or AUX Timeout conditions - not during normal operation.
- * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
- * at most within ~240usec. That means,
- * increasing this timeout will not affect normal operation,
- * and we'll timeout after
- * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
- * This timeout is especially important for
- * resume from S3 and CTS. */
- SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
-};
-
-struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
- struct i2caux *i2caux,
- struct ddc *ddc)
-{
- enum gpio_ddc_line line;
- struct i2c_engine *engine = NULL;
-
- if (get_hw_supported_ddc_line(ddc, &line))
- engine = i2caux->i2c_sw_engines[line];
-
- if (!engine)
- engine = i2caux->i2c_generic_sw_engine;
-
- if (!engine)
- return NULL;
-
- if (!engine->base.funcs->acquire(&engine->base, ddc))
- return NULL;
-
- return engine;
-}
-
-struct aux_engine *dal_i2caux_acquire_aux_engine(
- struct i2caux *i2caux,
- struct ddc *ddc)
-{
- enum gpio_ddc_line line;
- struct aux_engine *engine;
-
- if (!get_hw_supported_ddc_line(ddc, &line))
- return NULL;
-
- engine = i2caux->aux_engines[line];
-
- if (!engine)
- return NULL;
-
- if (!engine->base.funcs->acquire(&engine->base, ddc))
- return NULL;
-
- return engine;
-}
-
-void dal_i2caux_release_engine(
- struct i2caux *i2caux,
- struct engine *engine)
-{
- engine->funcs->release_engine(engine);
-
- dal_ddc_close(engine->ddc);
-
- engine->ddc = NULL;
-}
-
-void dal_i2caux_construct(
- struct i2caux *i2caux,
- struct dc_context *ctx)
-{
- uint32_t i = 0;
-
- i2caux->ctx = ctx;
- do {
- i2caux->i2c_sw_engines[i] = NULL;
- i2caux->i2c_hw_engines[i] = NULL;
- i2caux->aux_engines[i] = NULL;
-
- ++i;
- } while (i < GPIO_DDC_LINE_COUNT);
-
- i2caux->i2c_generic_sw_engine = NULL;
- i2caux->i2c_generic_hw_engine = NULL;
-
- i2caux->aux_timeout_period =
- SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD;
-
- if (ctx->dce_version >= DCE_VERSION_11_2) {
- i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED_100KHZ;
- i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED_100KHZ;
- } else {
- i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED;
- i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED;
- }
-}
-
-void dal_i2caux_destruct(
- struct i2caux *i2caux)
-{
- uint32_t i = 0;
-
- if (i2caux->i2c_generic_hw_engine)
- i2caux->i2c_generic_hw_engine->funcs->destroy(
- &i2caux->i2c_generic_hw_engine);
-
- if (i2caux->i2c_generic_sw_engine)
- i2caux->i2c_generic_sw_engine->funcs->destroy(
- &i2caux->i2c_generic_sw_engine);
-
- do {
- if (i2caux->aux_engines[i])
- i2caux->aux_engines[i]->funcs->destroy(
- &i2caux->aux_engines[i]);
-
- if (i2caux->i2c_hw_engines[i])
- i2caux->i2c_hw_engines[i]->funcs->destroy(
- &i2caux->i2c_hw_engines[i]);
-
- if (i2caux->i2c_sw_engines[i])
- i2caux->i2c_sw_engines[i]->funcs->destroy(
- &i2caux->i2c_sw_engines[i]);
-
- ++i;
- } while (i < GPIO_DDC_LINE_COUNT);
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h
deleted file mode 100644
index 64f51bb06915..000000000000
--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_I2C_AUX_H__
-#define __DAL_I2C_AUX_H__
-
-uint32_t dal_i2caux_get_reference_clock(
- struct dc_bios *bios);
-
-struct i2caux;
-
-struct engine;
-
-struct i2caux_funcs {
- void (*destroy)(struct i2caux **ptr);
- struct i2c_engine * (*acquire_i2c_sw_engine)(
- struct i2caux *i2caux,
- struct ddc *ddc);
- struct i2c_engine * (*acquire_i2c_hw_engine)(
- struct i2caux *i2caux,
- struct ddc *ddc);
- struct aux_engine * (*acquire_aux_engine)(
- struct i2caux *i2caux,
- struct ddc *ddc);
- void (*release_engine)(
- struct i2caux *i2caux,
- struct engine *engine);
-};
-
-struct i2c_engine;
-struct aux_engine;
-
-struct i2caux {
- struct dc_context *ctx;
- const struct i2caux_funcs *funcs;
- /* On ASIC we have certain amount of lines with HW DDC engine
- * (4, 6, or maybe more in the future).
- * For every such line, we create separate HW DDC engine
- * (since we have these engines in HW) and separate SW DDC engine
- * (to allow concurrent use of few lines).
- * In similar way we have AUX engines. */
-
- /* I2C SW engines, per DDC line.
- * Only lines with HW DDC support will be initialized */
- struct i2c_engine *i2c_sw_engines[GPIO_DDC_LINE_COUNT];
-
- /* I2C HW engines, per DDC line.
- * Only lines with HW DDC support will be initialized */
- struct i2c_engine *i2c_hw_engines[GPIO_DDC_LINE_COUNT];
-
- /* AUX engines, per DDC line.
- * Only lines with HW AUX support will be initialized */
- struct aux_engine *aux_engines[GPIO_DDC_LINE_COUNT];
-
- /* For all other lines, we can use
- * single instance of generic I2C HW engine
- * (since in HW, there is single instance of it)
- * or single instance of generic I2C SW engine.
- * AUX is not supported for other lines. */
-
- /* General-purpose I2C SW engine.
- * Can be assigned dynamically to any line per transaction */
- struct i2c_engine *i2c_generic_sw_engine;
-
- /* General-purpose I2C generic HW engine.
- * Can be assigned dynamically to almost any line per transaction */
- struct i2c_engine *i2c_generic_hw_engine;
-
- /* [anaumov] in DAL2, there is a Mutex */
-
- uint32_t aux_timeout_period;
-
- /* expressed in KHz */
- uint32_t default_i2c_sw_speed;
- uint32_t default_i2c_hw_speed;
-};
-
-void dal_i2caux_construct(
- struct i2caux *i2caux,
- struct dc_context *ctx);
-
-void dal_i2caux_release_engine(
- struct i2caux *i2caux,
- struct engine *engine);
-
-void dal_i2caux_destruct(
- struct i2caux *i2caux);
-
-void dal_i2caux_destroy(
- struct i2caux **ptr);
-
-struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
- struct i2caux *i2caux,
- struct ddc *ddc);
-
-struct aux_engine *dal_i2caux_acquire_aux_engine(
- struct i2caux *i2caux,
- struct ddc *ddc);
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
index 47ef90495376..fe6301cb8681 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
@@ -78,7 +78,7 @@ struct csdp_ref_clk_ds_params {
};
struct pixel_clk_params {
- uint32_t requested_pix_clk; /* in KHz */
+ uint32_t requested_pix_clk_100hz;
/*> Requested Pixel Clock
* (based on Video Timing standard used for requested mode)*/
uint32_t requested_sym_clk; /* in KHz */
@@ -104,9 +104,9 @@ struct pixel_clk_params {
* with actually calculated Clock and reference Crystal frequency
*/
struct pll_settings {
- uint32_t actual_pix_clk;
- uint32_t adjusted_pix_clk;
- uint32_t calculated_pix_clk;
+ uint32_t actual_pix_clk_100hz;
+ uint32_t adjusted_pix_clk_100hz;
+ uint32_t calculated_pix_clk_100hz;
uint32_t vco_freq;
uint32_t reference_freq;
uint32_t reference_divider;
@@ -166,6 +166,10 @@ struct clock_source_funcs {
struct clock_source *,
struct pixel_clk_params *,
struct pll_settings *);
+ bool (*get_pixel_clk_frequency_100hz)(
+ struct clock_source *clock_source,
+ unsigned int inst,
+ unsigned int *pixel_clk_khz);
};
struct clock_source {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
index 94fc31080fda..2e61a22ef4b2 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
@@ -30,7 +30,7 @@ enum dc_status {
DC_OK = 1,
DC_NO_CONTROLLER_RESOURCE = 2,
- DC_NO_STREAM_ENG_RESOURCE = 3,
+ DC_NO_STREAM_ENC_RESOURCE = 3,
DC_NO_CLOCK_SOURCE_RESOURCE = 4,
DC_FAIL_CONTROLLER_VALIDATE = 5,
DC_FAIL_ENC_VALIDATE = 6,
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 b168a5e9dd9d..986ed1728644 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -146,7 +146,7 @@ struct resource_pool {
struct mpc *mpc;
struct pp_smu_funcs_rv *pp_smu;
struct pp_smu_display_requirement_rv pp_smu_req;
- struct aux_engine *engines[MAX_PIPES];
+ struct dce_aux *engines[MAX_PIPES];
struct dce_i2c_hw *hw_i2cs[MAX_PIPES];
struct dce_i2c_sw *sw_i2cs[MAX_PIPES];
bool i2c_hw_buffer_in_use;
@@ -180,13 +180,8 @@ struct resource_pool {
const struct resource_caps *res_cap;
};
-struct dcn_fe_clocks {
- int dppclk_khz;
-};
-
struct dcn_fe_bandwidth {
- struct dcn_fe_clocks calc;
- struct dcn_fe_clocks cur;
+ int dppclk_khz;
};
struct stream_resource {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
index 538b83303b86..16fd4dc6c4dd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
@@ -64,13 +64,6 @@ void dal_ddc_i2c_payloads_add(
uint8_t *data,
bool write);
-void dal_ddc_aux_payloads_add(
- struct aux_payloads *payloads,
- uint32_t address,
- uint32_t len,
- uint8_t *data,
- bool write);
-
struct ddc_service_init_data {
struct graphics_object_id id;
struct dc_context *ctx;
@@ -103,12 +96,10 @@ bool dal_ddc_service_query_ddc_data(
uint32_t read_size);
int dc_link_aux_transfer(struct ddc_service *ddc,
- unsigned int address,
- uint8_t *reply,
- void *buffer,
- unsigned int size,
- enum aux_transaction_type type,
- enum i2caux_transaction_action action);
+ struct aux_payload *payload);
+
+bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *payload);
void dal_ddc_service_write_scdc_data(
struct ddc_service *ddc_service,
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 02f757dd70d4..9d2d8e51306c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -39,6 +39,18 @@ enum segment_order {
segment_order__non_contiguous,
};
+struct dcn_hubbub_wm_set {
+ uint32_t wm_set;
+ uint32_t data_urgent;
+ uint32_t pte_meta_urgent;
+ uint32_t sr_enter;
+ uint32_t sr_exit;
+ uint32_t dram_clk_chanage;
+};
+
+struct dcn_hubbub_wm {
+ struct dcn_hubbub_wm_set sets[4];
+};
struct hubbub_funcs {
void (*update_dchub)(
@@ -58,7 +70,14 @@ struct hubbub_funcs {
bool (*dcc_support_pixel_format)(
enum surface_pixel_format format,
unsigned int *bytes_per_element);
+
+ void (*wm_read_state)(struct hubbub *hubbub,
+ struct dcn_hubbub_wm *wm);
};
+struct hubbub {
+ const struct hubbub_funcs *funcs;
+ struct dc_context *ctx;
+};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
index cb85eaa9857f..cbaa43853611 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
@@ -27,16 +27,22 @@
#include "dm_services_types.h"
+/* If HW itself ever powered down it will be 0.
+ * fwDmcuInit will write to 1.
+ * Driver will only call MCP init if current state is 1,
+ * and the MCP command will transition this to 2.
+ */
enum dmcu_state {
- DMCU_NOT_INITIALIZED = 0,
- DMCU_RUNNING = 1
+ DMCU_UNLOADED = 0,
+ DMCU_LOADED_UNINITIALIZED = 1,
+ DMCU_RUNNING = 2,
};
struct dmcu_version {
- unsigned int date;
- unsigned int month;
- unsigned int year;
unsigned int interface_version;
+ unsigned int abm_version;
+ unsigned int psr_version;
+ unsigned int build_version;
};
struct dmcu {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
index e894e649ce5a..fb7967b39edb 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -39,6 +39,11 @@ struct dpp {
};
+struct dpp_input_csc_matrix {
+ enum dc_color_space color_space;
+ uint16_t regval[12];
+};
+
struct dpp_grph_csc_adjustment {
struct fixed31_32 temperature_matrix[CSC_TEMPERATURE_MATRIX_SIZE];
enum graphics_gamut_adjust_type gamut_adjust_type;
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 04c6989aac58..1cd07e94ee63 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -78,7 +78,8 @@ struct hubp_funcs {
bool (*hubp_program_surface_flip_and_addr)(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ uint8_t vmid);
void (*hubp_program_pte_vm)(
struct hubp *hubp,
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 c20fdcaac53b..c9d3e37e9531 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
@@ -153,6 +153,7 @@ struct link_encoder_funcs {
void (*enable_hpd)(struct link_encoder *enc);
void (*disable_hpd)(struct link_encoder *enc);
bool (*is_dig_enabled)(struct link_encoder *enc);
+ unsigned int (*get_dig_frontend)(struct link_encoder *enc);
void (*destroy)(struct link_encoder **enc);
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
index 06df02ddff6a..da89c2edb07c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
@@ -31,7 +31,7 @@
#include "dml/display_mode_structs.h"
struct dchub_init_data;
-struct cstate_pstate_watermarks_st1 {
+struct cstate_pstate_watermarks_st {
uint32_t cstate_exit_ns;
uint32_t cstate_enter_plus_exit_ns;
uint32_t pstate_change_ns;
@@ -40,7 +40,7 @@ struct cstate_pstate_watermarks_st1 {
struct dcn_watermarks {
uint32_t pte_meta_urgent_ns;
uint32_t urgent_ns;
- struct cstate_pstate_watermarks_st1 cstate_pstate;
+ struct cstate_pstate_watermarks_st cstate_pstate;
};
struct dcn_watermark_set {
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 53a9b64df11a..4051493557bc 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
@@ -161,6 +161,10 @@ struct stream_encoder_funcs {
void (*set_avmute)(
struct stream_encoder *enc, bool enable);
+ void (*dig_connect_to_otg)(
+ struct stream_encoder *enc,
+ int tg_inst);
+
};
#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 af700c7dac50..03ae941895f3 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
@@ -134,15 +134,29 @@ struct dc_crtc_timing;
struct drr_params;
+union vline_config;
+
+
+enum vline_select {
+ VLINE0,
+ VLINE1,
+ VLINE2
+};
+
struct timing_generator_funcs {
bool (*validate_timing)(struct timing_generator *tg,
const struct dc_crtc_timing *timing);
void (*program_timing)(struct timing_generator *tg,
const struct dc_crtc_timing *timing,
bool use_vbios);
- void (*program_vline_interrupt)(struct timing_generator *optc,
+ void (*program_vline_interrupt)(
+ struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing,
- unsigned long long vsync_delta);
+ enum vline_select vline,
+ const union vline_config *vline_config);
+
+ void (*program_vupdate_interrupt)(struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing);
bool (*enable_crtc)(struct timing_generator *tg);
bool (*disable_crtc)(struct timing_generator *tg);
bool (*is_counter_moving)(struct timing_generator *tg);
@@ -159,6 +173,8 @@ struct timing_generator_funcs {
bool (*get_otg_active_size)(struct timing_generator *optc,
uint32_t *otg_active_width,
uint32_t *otg_active_height);
+ bool (*is_matching_timing)(struct timing_generator *tg,
+ const struct dc_crtc_timing *otg_timing);
void (*set_early_control)(struct timing_generator *tg,
uint32_t early_cntl);
void (*wait_for_state)(struct timing_generator *tg,
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h
index 5d155d36d353..037beb0a2a27 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
+ * Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -23,30 +23,27 @@
*
*/
-#include "dm_services.h"
+#ifndef DAL_DC_INC_HW_VMID_H_
+#define DAL_DC_INC_HW_VMID_H_
-/*
- * Pre-requisites: headers required by header of this unit
- */
-#include "include/i2caux_interface.h"
-
-/*
- * Header of this unit
- */
-
-#include "engine.h"
+#include "core_types.h"
+#include "dchubbub.h"
-void dal_i2caux_construct_engine(
- struct engine *engine,
- struct dc_context *ctx)
-{
- engine->ddc = NULL;
- engine->ctx = ctx;
-}
+struct dcn_vmid_registers {
+ uint32_t CNTL;
+ uint32_t PAGE_TABLE_BASE_ADDR_HI32;
+ uint32_t PAGE_TABLE_BASE_ADDR_LO32;
+ uint32_t PAGE_TABLE_START_ADDR_HI32;
+ uint32_t PAGE_TABLE_START_ADDR_LO32;
+ uint32_t PAGE_TABLE_END_ADDR_HI32;
+ uint32_t PAGE_TABLE_END_ADDR_LO32;
+};
-void dal_i2caux_destruct_engine(
- struct engine *engine)
-{
- /* nothing to do */
-}
+struct dcn_vmid_page_table_config {
+ uint64_t page_table_start_addr;
+ uint64_t page_table_end_addr;
+ enum dcn_hubbub_page_table_depth depth;
+ enum dcn_hubbub_page_table_block_size block_size;
+};
+#endif /* DAL_DC_INC_HW_VMID_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index d6a85f48b6d1..341b4810288c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -70,6 +70,8 @@ struct hw_sequencer_funcs {
void (*init_hw)(struct dc *dc);
+ void (*init_pipes)(struct dc *dc, struct dc_state *context);
+
enum dc_status (*apply_ctx_to_hw)(
struct dc *dc, struct dc_state *context);
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h
index c48c61f540a8..193407f76a80 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
+ * Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -23,21 +23,34 @@
*
*/
-#ifndef __DAL_I2C_SW_ENGINE_DCE110_H__
-#define __DAL_I2C_SW_ENGINE_DCE110_H__
+#ifndef DC_INC_VM_HELPER_H_
+#define DC_INC_VM_HELPER_H_
-struct i2c_sw_engine_dce110 {
- struct i2c_sw_engine base;
- uint32_t engine_id;
+#include "dc_types.h"
+
+#define MAX_VMID 16
+#define MAX_HUBP 6
+
+struct vmid_usage {
+ uint16_t vmid_usage[2];
};
-struct i2c_sw_engine_dce110_create_arg {
- uint32_t engine_id;
- uint32_t default_speed;
- struct dc_context *ctx;
+struct vm_helper {
+ unsigned int num_vmid;
+ unsigned int num_hubp;
+ unsigned int num_vmids_available;
+ uint64_t ptb_assigned_to_vmid[MAX_VMID];
+ struct vmid_usage hubp_vmid_usage[MAX_HUBP];
};
-struct i2c_engine *dal_i2c_sw_engine_dce110_create(
- const struct i2c_sw_engine_dce110_create_arg *arg);
+uint8_t get_vmid_for_ptb(
+ struct vm_helper *vm_helper,
+ int64_t ptb,
+ uint8_t pipe_idx);
+
+void init_vm_helper(
+ struct vm_helper *vm_helper,
+ unsigned int num_vmid,
+ unsigned int num_hubp);
-#endif
+#endif /* DC_INC_VM_HELPER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/irq_types.h b/drivers/gpu/drm/amd/display/dc/irq_types.h
index 0b5f3a278c22..d0ccd81ad5b4 100644
--- a/drivers/gpu/drm/amd/display/dc/irq_types.h
+++ b/drivers/gpu/drm/amd/display/dc/irq_types.h
@@ -144,6 +144,14 @@ enum dc_irq_source {
DC_IRQ_SOURCE_DC5_VLINE0,
DC_IRQ_SOURCE_DC6_VLINE0,
+ DC_IRQ_SOURCE_DC1_VLINE1,
+ DC_IRQ_SOURCE_DC2_VLINE1,
+ DC_IRQ_SOURCE_DC3_VLINE1,
+ DC_IRQ_SOURCE_DC4_VLINE1,
+ DC_IRQ_SOURCE_DC5_VLINE1,
+ DC_IRQ_SOURCE_DC6_VLINE1,
+
+
DAL_IRQ_SOURCES_NUMBER
};
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 7fd78a696800..01bf01a34a08 100644
--- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h
+++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
@@ -211,8 +211,8 @@ struct bp_pixel_clock_parameters {
/* signal_type -> Encoder Mode - needed by VBIOS Exec table */
enum signal_type signal_type;
/* Adjusted Pixel Clock (after VBIOS exec table)
- * that becomes Target Pixel Clock (KHz) */
- uint32_t target_pixel_clock;
+ * that becomes Target Pixel Clock (100 Hz units) */
+ uint32_t target_pixel_clock_100hz;
/* Calculated Reference divider of Display PLL */
uint32_t reference_divider;
/* Calculated Feedback divider of Display PLL */
diff --git a/drivers/gpu/drm/amd/display/include/gpio_interface.h b/drivers/gpu/drm/amd/display/include/gpio_interface.h
index e4fd31024b92..7de64195dc33 100644
--- a/drivers/gpu/drm/amd/display/include/gpio_interface.h
+++ b/drivers/gpu/drm/amd/display/include/gpio_interface.h
@@ -59,6 +59,14 @@ enum gpio_result dal_gpio_change_mode(
struct gpio *gpio,
enum gpio_mode mode);
+/* Lock Pin */
+enum gpio_result dal_gpio_lock_pin(
+ struct gpio *gpio);
+
+/* Unlock Pin */
+enum gpio_result dal_gpio_unlock_pin(
+ struct gpio *gpio);
+
/* Get the GPIO id */
enum gpio_id dal_gpio_get_id(
const struct gpio *gpio);
diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/include/i2caux_interface.h
index 13a3c82d118f..bb012cb1a9f5 100644
--- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h
+++ b/drivers/gpu/drm/amd/display/include/i2caux_interface.h
@@ -40,9 +40,19 @@ struct aux_payload {
/* set following flag to write data,
* reset it to read data */
bool write;
+ bool mot;
uint32_t address;
uint8_t length;
uint8_t *data;
+ /*
+ * used to return the reply type of the transaction
+ * ignored if NULL
+ */
+ uint8_t *reply;
+ /* expressed in milliseconds
+ * zero means "use default value"
+ */
+ uint32_t defer_delay;
};
struct aux_command {
@@ -66,27 +76,4 @@ union aux_config {
uint32_t raw;
};
-struct i2caux;
-
-struct i2caux *dal_i2caux_create(
- struct dc_context *ctx);
-
-bool dal_i2caux_submit_i2c_command(
- struct i2caux *i2caux,
- struct ddc *ddc,
- struct i2c_command *cmd);
-
-bool dal_i2caux_submit_aux_command(
- struct i2caux *i2caux,
- struct ddc *ddc,
- struct aux_command *cmd);
-
-void dal_i2caux_configure_aux(
- struct i2caux *i2caux,
- struct ddc *ddc,
- union aux_config cfg);
-
-void dal_i2caux_destroy(
- struct i2caux **ptr);
-
#endif
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
index 479b77c2e89e..0fbc8fbc3541 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -823,7 +823,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
bool is_clipped = false;
struct fixed31_32 sdr_white_level;
- if (fs_params == NULL || fs_params->max_content == 0 ||
+ if (fs_params->max_content == 0 ||
fs_params->max_display == 0)
return false;
@@ -1508,7 +1508,7 @@ static bool map_regamma_hw_to_x_user(
struct hw_x_point *coords = coords_x;
const struct pwl_float_data_ex *regamma = rgb_regamma;
- if (mapUserRamp) {
+ if (ramp && mapUserRamp) {
copy_rgb_regamma_to_coordinates_x(coords,
hw_points_num,
rgb_regamma);
@@ -1545,7 +1545,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
struct pwl_float_data *rgb_user = NULL;
struct pwl_float_data_ex *rgb_regamma = NULL;
- struct gamma_pixel *axix_x = NULL;
+ struct gamma_pixel *axis_x = NULL;
struct pixel_gamma_point *coeff = NULL;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
bool ret = false;
@@ -1555,47 +1555,54 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
/* we can use hardcoded curve for plain SRGB TF */
if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
- output_tf->tf == TRANSFER_FUNCTION_SRGB &&
- (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256)))
- return true;
+ output_tf->tf == TRANSFER_FUNCTION_SRGB) {
+ if (ramp == NULL)
+ return true;
+ if (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256))
+ return true;
+ }
output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
- rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
+ if (ramp && (mapUserRamp || ramp->type != GAMMA_RGB_256)) {
+ rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
sizeof(*rgb_user),
GFP_KERNEL);
- if (!rgb_user)
- goto rgb_user_alloc_fail;
+ if (!rgb_user)
+ goto rgb_user_alloc_fail;
+
+ axis_x = kvcalloc(ramp->num_entries + 3, sizeof(*axis_x),
+ GFP_KERNEL);
+ if (!axis_x)
+ goto axis_x_alloc_fail;
+
+ dividers.divider1 = dc_fixpt_from_fraction(3, 2);
+ dividers.divider2 = dc_fixpt_from_int(2);
+ dividers.divider3 = dc_fixpt_from_fraction(5, 2);
+
+ build_evenly_distributed_points(
+ axis_x,
+ ramp->num_entries,
+ dividers);
+
+ if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
+ scale_gamma(rgb_user, ramp, dividers);
+ else if (ramp->type == GAMMA_RGB_FLOAT_1024)
+ scale_gamma_dx(rgb_user, ramp, dividers);
+ }
+
rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
sizeof(*rgb_regamma),
GFP_KERNEL);
if (!rgb_regamma)
goto rgb_regamma_alloc_fail;
- axix_x = kvcalloc(ramp->num_entries + 3, sizeof(*axix_x),
- GFP_KERNEL);
- if (!axix_x)
- goto axix_x_alloc_fail;
+
coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
GFP_KERNEL);
if (!coeff)
goto coeff_alloc_fail;
- dividers.divider1 = dc_fixpt_from_fraction(3, 2);
- dividers.divider2 = dc_fixpt_from_int(2);
- dividers.divider3 = dc_fixpt_from_fraction(5, 2);
-
tf = output_tf->tf;
-
- build_evenly_distributed_points(
- axix_x,
- ramp->num_entries,
- dividers);
-
- if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
- scale_gamma(rgb_user, ramp, dividers);
- else if (ramp->type == GAMMA_RGB_FLOAT_1024)
- scale_gamma_dx(rgb_user, ramp, dividers);
-
if (tf == TRANSFER_FUNCTION_PQ) {
tf_pts->end_exponent = 7;
tf_pts->x_point_at_y1_red = 125;
@@ -1623,22 +1630,22 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false);
}
map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
- coordinates_x, axix_x, rgb_regamma,
+ coordinates_x, axis_x, rgb_regamma,
MAX_HW_POINTS, tf_pts,
- (mapUserRamp || ramp->type != GAMMA_RGB_256) &&
- ramp->type != GAMMA_CS_TFM_1D);
+ (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) &&
+ (ramp && ramp->type != GAMMA_CS_TFM_1D));
- if (ramp->type == GAMMA_CS_TFM_1D)
+ if (ramp && ramp->type == GAMMA_CS_TFM_1D)
apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
ret = true;
kvfree(coeff);
coeff_alloc_fail:
- kvfree(axix_x);
-axix_x_alloc_fail:
kvfree(rgb_regamma);
rgb_regamma_alloc_fail:
+ kvfree(axis_x);
+axis_x_alloc_fail:
kvfree(rgb_user);
rgb_user_alloc_fail:
return ret;
@@ -1758,69 +1765,85 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
{
struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
struct dividers dividers;
-
struct pwl_float_data *rgb_user = NULL;
struct pwl_float_data_ex *curve = NULL;
struct gamma_pixel *axis_x = NULL;
struct pixel_gamma_point *coeff = NULL;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
+ uint32_t i;
bool ret = false;
if (input_tf->type == TF_TYPE_BYPASS)
return false;
- /* we can use hardcoded curve for plain SRGB TF */
+ /* we can use hardcoded curve for plain SRGB TF
+ * If linear, it's bypass if on user ramp
+ */
if (input_tf->type == TF_TYPE_PREDEFINED &&
- input_tf->tf == TRANSFER_FUNCTION_SRGB &&
- (!mapUserRamp &&
- (ramp->type == GAMMA_RGB_256 || ramp->num_entries == 0)))
+ (input_tf->tf == TRANSFER_FUNCTION_SRGB ||
+ input_tf->tf == TRANSFER_FUNCTION_LINEAR) &&
+ !mapUserRamp)
return true;
input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
- rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
- sizeof(*rgb_user),
- GFP_KERNEL);
- if (!rgb_user)
- goto rgb_user_alloc_fail;
+ if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) {
+ rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
+ sizeof(*rgb_user),
+ GFP_KERNEL);
+ if (!rgb_user)
+ goto rgb_user_alloc_fail;
+
+ axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x),
+ GFP_KERNEL);
+ if (!axis_x)
+ goto axis_x_alloc_fail;
+
+ dividers.divider1 = dc_fixpt_from_fraction(3, 2);
+ dividers.divider2 = dc_fixpt_from_int(2);
+ dividers.divider3 = dc_fixpt_from_fraction(5, 2);
+
+ build_evenly_distributed_points(
+ axis_x,
+ ramp->num_entries,
+ dividers);
+
+ scale_gamma(rgb_user, ramp, dividers);
+ }
+
curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!curve)
goto curve_alloc_fail;
- axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x),
- GFP_KERNEL);
- if (!axis_x)
- goto axis_x_alloc_fail;
+
coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!coeff)
goto coeff_alloc_fail;
- dividers.divider1 = dc_fixpt_from_fraction(3, 2);
- dividers.divider2 = dc_fixpt_from_int(2);
- dividers.divider3 = dc_fixpt_from_fraction(5, 2);
-
tf = input_tf->tf;
- build_evenly_distributed_points(
- axis_x,
- ramp->num_entries,
- dividers);
-
- if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
- scale_gamma(rgb_user, ramp, dividers);
- else if (ramp->type == GAMMA_RGB_FLOAT_1024)
- scale_gamma_dx(rgb_user, ramp, dividers);
-
if (tf == TRANSFER_FUNCTION_PQ)
build_de_pq(curve,
MAX_HW_POINTS,
coordinates_x);
- else
+ else if (tf == TRANSFER_FUNCTION_SRGB ||
+ tf == TRANSFER_FUNCTION_BT709)
build_degamma(curve,
MAX_HW_POINTS,
coordinates_x,
- tf == TRANSFER_FUNCTION_SRGB ? true:false);
+ tf == TRANSFER_FUNCTION_SRGB ? true : false);
+ else if (tf == TRANSFER_FUNCTION_LINEAR) {
+ // just copy coordinates_x into curve
+ i = 0;
+ while (i != MAX_HW_POINTS + 1) {
+ curve[i].r = coordinates_x[i].x;
+ curve[i].g = curve[i].r;
+ curve[i].b = curve[i].r;
+ i++;
+ }
+ } else
+ goto invalid_tf_fail;
tf_pts->end_exponent = 0;
tf_pts->x_point_at_y1_red = 1;
@@ -1830,23 +1853,21 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
coordinates_x, axis_x, curve,
MAX_HW_POINTS, tf_pts,
- mapUserRamp && ramp->type != GAMMA_CUSTOM);
- if (ramp->type == GAMMA_CUSTOM)
- apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
+ mapUserRamp && ramp && ramp->type == GAMMA_RGB_256);
ret = true;
+invalid_tf_fail:
kvfree(coeff);
coeff_alloc_fail:
- kvfree(axis_x);
-axis_x_alloc_fail:
kvfree(curve);
curve_alloc_fail:
+ kvfree(axis_x);
+axis_x_alloc_fail:
kvfree(rgb_user);
rgb_user_alloc_fail:
return ret;
-
}
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 1544ed3f1747..94a84bc57c7a 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -108,8 +108,8 @@ static unsigned int calc_duration_in_us_from_v_total(
{
unsigned int duration_in_us =
(unsigned int)(div64_u64(((unsigned long long)(v_total)
- * 1000) * stream->timing.h_total,
- stream->timing.pix_clk_khz));
+ * 10000) * stream->timing.h_total,
+ stream->timing.pix_clk_100hz));
return duration_in_us;
}
@@ -126,7 +126,7 @@ static unsigned int calc_v_total_from_refresh(
refresh_in_uhz)));
v_total = div64_u64(div64_u64(((unsigned long long)(
- frame_duration_in_ns) * stream->timing.pix_clk_khz),
+ frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
stream->timing.h_total), 1000000);
/* v_total cannot be less than nominal */
@@ -152,7 +152,7 @@ static unsigned int calc_v_total_from_duration(
duration_in_us = vrr->max_duration_in_us;
v_total = div64_u64(div64_u64(((unsigned long long)(
- duration_in_us) * stream->timing.pix_clk_khz),
+ duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
stream->timing.h_total), 1000);
/* v_total cannot be less than nominal */
@@ -227,7 +227,7 @@ static void update_v_total_for_static_ramp(
}
v_total = div64_u64(div64_u64(((unsigned long long)(
- current_duration_in_us) * stream->timing.pix_clk_khz),
+ current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
stream->timing.h_total), 1000);
in_out_vrr->adjust.v_total_min = v_total;
@@ -461,6 +461,26 @@ bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
return false;
}
+static void build_vrr_infopacket_header_vtem(enum signal_type signal,
+ struct dc_info_packet *infopacket)
+{
+ // HEADER
+
+ // HB0, HB1, HB2 indicates PacketType VTEMPacket
+ infopacket->hb0 = 0x7F;
+ infopacket->hb1 = 0xC0;
+ infopacket->hb2 = 0x00;
+ /* HB3 Bit Fields
+ * Reserved :1 = 0
+ * Sync :1 = 0
+ * VFR :1 = 1
+ * Ds_Type :2 = 0
+ * End :1 = 0
+ * New :1 = 0
+ */
+ infopacket->hb3 = 0x20;
+}
+
static void build_vrr_infopacket_header_v1(enum signal_type signal,
struct dc_info_packet *infopacket,
unsigned int *payload_size)
@@ -559,6 +579,54 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal,
}
}
+static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr,
+ struct dc_info_packet *infopacket)
+{
+ /* dc_info_packet to VtemPacket Translation of Bit-fields,
+ * SB[6]
+ * unsigned char VRR_EN :1
+ * unsigned char M_CONST :1
+ * unsigned char Reserved2 :2
+ * unsigned char FVA_Factor_M1 :4
+ * SB[7]
+ * unsigned char Base_Vfront :8
+ * SB[8]
+ * unsigned char Base_Refresh_Rate_98 :2
+ * unsigned char RB :1
+ * unsigned char Reserved3 :5
+ * SB[9]
+ * unsigned char Base_RefreshRate_07 :8
+ */
+ unsigned int fieldRateInHz;
+
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+ vrr->state == VRR_STATE_ACTIVE_FIXED){
+ infopacket->sb[6] |= 0x80; //VRR_EN Bit = 1
+ } else {
+ infopacket->sb[6] &= 0x7F; //VRR_EN Bit = 0
+ }
+
+ if (!stream->timing.vic) {
+ infopacket->sb[7] = stream->timing.v_front_porch;
+
+ /* TODO: In dal2, we check mode flags for a reduced blanking timing.
+ * Need a way to relay that information to this function.
+ * if("ReducedBlanking")
+ * {
+ * infopacket->sb[8] |= 0x20; //Set 3rd bit to 1
+ * }
+ */
+ fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/
+ (stream->timing.h_total * stream->timing.v_total);
+
+ infopacket->sb[8] |= ((fieldRateInHz & 0x300) >> 2);
+ infopacket->sb[9] |= fieldRateInHz & 0xFF;
+
+ }
+ infopacket->valid = true;
+}
+
static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr,
struct dc_info_packet *infopacket)
{
@@ -672,6 +740,19 @@ static void build_vrr_infopacket_v2(enum signal_type signal,
infopacket->valid = true;
}
+static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr,
+ struct dc_info_packet *infopacket)
+{
+ //VTEM info packet for HdmiVrr
+
+ //VTEM Packet is structured differently
+ build_vrr_infopacket_header_vtem(stream->signal, infopacket);
+ build_vrr_vtem_infopacket_data(stream, vrr, infopacket);
+
+ infopacket->valid = true;
+}
+
void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
const struct dc_stream_state *stream,
const struct mod_vrr_params *vrr,
@@ -679,18 +760,21 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
const enum color_transfer_func *app_tf,
struct dc_info_packet *infopacket)
{
- /* SPD info packet for FreeSync */
-
- /* Check if Freesync is supported. Return if false. If true,
+ /* SPD info packet for FreeSync
+ * VTEM info packet for HdmiVRR
+ * Check if Freesync is supported. Return if false. If true,
* set the corresponding bit in the info packet
*/
- if (!vrr->supported || !vrr->send_vsif)
+ if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM))
return;
switch (packet_type) {
case PACKET_TYPE_FS2:
build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
break;
+ case PACKET_TYPE_VTEM:
+ build_vrr_infopacket_vtem(stream, vrr, infopacket);
+ break;
case PACKET_TYPE_VRR:
case PACKET_TYPE_FS1:
default:
@@ -739,7 +823,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
return;
in_out_vrr->state = in_config->state;
- in_out_vrr->send_vsif = in_config->vsif_supported;
+ in_out_vrr->send_info_frame = in_config->vsif_supported;
if (in_config->state == VRR_STATE_UNSUPPORTED) {
in_out_vrr->state = VRR_STATE_UNSUPPORTED;
@@ -972,7 +1056,7 @@ unsigned long long mod_freesync_calc_nominal_field_rate(
unsigned long long nominal_field_rate_in_uhz = 0;
/* Calculate nominal field rate for stream */
- nominal_field_rate_in_uhz = stream->timing.pix_clk_khz;
+ nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10;
nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
stream->timing.h_total);
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 949a8b62aa98..4222e403b151 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
@@ -104,7 +104,7 @@ struct mod_vrr_params_fixed_refresh {
struct mod_vrr_params {
bool supported;
- bool send_vsif;
+ bool send_info_frame;
enum mod_vrr_state state;
uint32_t min_refresh_in_uhz;
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h
index 1bd02c0ac30c..b711e7e6c204 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h
@@ -41,7 +41,8 @@ enum color_transfer_func {
enum vrr_packet_type {
PACKET_TYPE_VRR,
PACKET_TYPE_FS1,
- PACKET_TYPE_FS2
+ PACKET_TYPE_FS2,
+ PACKET_TYPE_VTEM
};
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 00f63b7dd32f..3ba87b076287 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -41,6 +41,17 @@ static const unsigned char min_reduction_table[13] = {
static const unsigned char max_reduction_table[13] = {
0xf5, 0xe5, 0xd9, 0xcd, 0xb1, 0xa5, 0xa5, 0x80, 0x65, 0x4d, 0x4d, 0x4d, 0x32};
+/* ABM 2.2 Min Reduction effectively disabled (100% for all configs)*/
+static const unsigned char min_reduction_table_v_2_2[13] = {
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/* Possible ABM 2.2 Max Reduction configs from least aggressive to most aggressive
+ * 0 1 2 3 4 5 6 7 8 9 10 11 12
+ * 96.1 89.8 74.9 69.4 64.7 52.2 48.6 39.6 30.2 25.1 19.6 12.5 12.5 %
+ */
+static const unsigned char max_reduction_table_v_2_2[13] = {
+0xf5, 0xe5, 0xbf, 0xb1, 0xa5, 0x85, 0x7c, 0x65, 0x4d, 0x40, 0x32, 0x20, 0x20};
+
/* Predefined ABM configuration sets. We may have different configuration sets
* in order to satisfy different power/quality requirements.
*/
@@ -56,7 +67,15 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le
#define NUM_AGGR_LEVEL 4
#define NUM_POWER_FN_SEGS 8
#define NUM_BL_CURVE_SEGS 16
+#define IRAM_SIZE 256
+#define IRAM_RESERVE_AREA_START_V2 0xF0 // reserve 0xF0~0xF6 are write by DMCU only
+#define IRAM_RESERVE_AREA_END_V2 0xF6 // reserve 0xF0~0xF6 are write by DMCU only
+
+#define IRAM_RESERVE_AREA_START_V2_2 0xF0 // reserve 0xF0~0xFF are write by DMCU only
+#define IRAM_RESERVE_AREA_END_V2_2 0xFF // reserve 0xF0~0xFF are write by DMCU only
+
+#pragma pack(push, 1)
/* NOTE: iRAM is 256B in size */
struct iram_table_v_2 {
/* flags */
@@ -85,11 +104,10 @@ struct iram_table_v_2 {
/* For reading PSR State directly from IRAM */
uint8_t psr_state; /* 0xf0 */
- uint8_t dmcu_interface_version; /* 0xf1 */
- uint8_t dmcu_date_version_year_b0; /* 0xf2 */
- uint8_t dmcu_date_version_year_b1; /* 0xf3 */
- uint8_t dmcu_date_version_month; /* 0xf4 */
- uint8_t dmcu_date_version_day; /* 0xf5 */
+ uint8_t dmcu_mcp_interface_version; /* 0xf1 */
+ uint8_t dmcu_abm_feature_version; /* 0xf2 */
+ uint8_t dmcu_psr_feature_version; /* 0xf3 */
+ uint16_t dmcu_version; /* 0xf4 */
uint8_t dmcu_state; /* 0xf6 */
uint16_t blRampReduction; /* 0xf7 */
@@ -101,6 +119,52 @@ struct iram_table_v_2 {
uint8_t dummy9; /* 0xff */
};
+struct iram_table_v_2_2 {
+ /* flags */
+ uint16_t flags; /* 0x00 U16 */
+
+ /* parameters for ABM2.2 algorithm */
+ uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x02 U0.8 */
+ uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */
+ uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */
+ uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */
+ uint8_t hybridFactor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */
+ uint8_t contrastFactor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */
+ uint8_t deviation_gain[NUM_AGGR_LEVEL]; /* 0x5a U0.8 */
+ uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x5e U0.8 */
+ uint8_t pad[29]; /* 0x63 U0.8 */
+
+ /* parameters for crgb conversion */
+ uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */
+ uint16_t crgb_offset[NUM_POWER_FN_SEGS]; /* 0x90 U1.15 */
+ uint16_t crgb_slope[NUM_POWER_FN_SEGS]; /* 0xa0 U4.12 */
+
+ /* parameters for custom curve */
+ /* thresholds for brightness --> backlight */
+ uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS]; /* 0xb0 U16.0 */
+ /* offsets for brightness --> backlight */
+ uint16_t backlight_offsets[NUM_BL_CURVE_SEGS]; /* 0xd0 U16.0 */
+
+ /* For reading PSR State directly from IRAM */
+ uint8_t psr_state; /* 0xf0 */
+ uint8_t dmcu_mcp_interface_version; /* 0xf1 */
+ uint8_t dmcu_abm_feature_version; /* 0xf2 */
+ uint8_t dmcu_psr_feature_version; /* 0xf3 */
+ uint16_t dmcu_version; /* 0xf4 */
+ uint8_t dmcu_state; /* 0xf6 */
+
+ uint8_t dummy1; /* 0xf7 */
+ uint8_t dummy2; /* 0xf8 */
+ uint8_t dummy3; /* 0xf9 */
+ uint8_t dummy4; /* 0xfa */
+ uint8_t dummy5; /* 0xfb */
+ uint8_t dummy6; /* 0xfc */
+ uint8_t dummy7; /* 0xfd */
+ uint8_t dummy8; /* 0xfe */
+ uint8_t dummy9; /* 0xff */
+};
+#pragma pack(pop)
+
static uint16_t backlight_8_to_16(unsigned int backlight_8bit)
{
return (uint16_t)(backlight_8bit * 0x101);
@@ -143,11 +207,363 @@ static void fill_backlight_transform_table(struct dmcu_iram_parameters params,
}
}
+static void fill_backlight_transform_table_v_2_2(struct dmcu_iram_parameters params,
+ struct iram_table_v_2_2 *table)
+{
+ unsigned int i;
+ unsigned int num_entries = NUM_BL_CURVE_SEGS;
+ unsigned int query_input_8bit;
+ unsigned int query_output_8bit;
+ unsigned int lut_index;
+
+ table->backlight_thresholds[0] = 0;
+ table->backlight_offsets[0] = params.backlight_lut_array[0];
+ table->backlight_thresholds[num_entries-1] = 0xFFFF;
+ table->backlight_offsets[num_entries-1] =
+ params.backlight_lut_array[params.backlight_lut_array_size - 1];
+
+ /* Setup all brightness levels between 0% and 100% exclusive
+ * Fills brightness-to-backlight transform table. Backlight custom curve
+ * describes transform from brightness to backlight. It will be defined
+ * as set of thresholds and set of offsets, together, implying
+ * extrapolation of custom curve into 16 uniformly spanned linear
+ * segments. Each threshold/offset represented by 16 bit entry in
+ * format U4.10.
+ */
+ for (i = 1; i+1 < num_entries; i++) {
+ query_input_8bit = DIV_ROUNDUP((i * 256), num_entries);
+
+ lut_index = (params.backlight_lut_array_size - 1) * i / (num_entries - 1);
+ ASSERT(lut_index < params.backlight_lut_array_size);
+ query_output_8bit = params.backlight_lut_array[lut_index] >> 8;
+
+ table->backlight_thresholds[i] =
+ backlight_8_to_16(query_input_8bit);
+ table->backlight_offsets[i] =
+ backlight_8_to_16(query_output_8bit);
+ }
+}
+
+void fill_iram_v_2(struct iram_table_v_2 *ram_table, struct dmcu_iram_parameters params)
+{
+ unsigned int set = params.set;
+
+ ram_table->flags = 0x0;
+ ram_table->deviation_gain = 0xb3;
+
+ ram_table->blRampReduction =
+ cpu_to_be16(params.backlight_ramping_reduction);
+ ram_table->blRampStart =
+ cpu_to_be16(params.backlight_ramping_start);
+
+ ram_table->min_reduction[0][0] = min_reduction_table[abm_config[set][0]];
+ ram_table->min_reduction[1][0] = min_reduction_table[abm_config[set][0]];
+ ram_table->min_reduction[2][0] = min_reduction_table[abm_config[set][0]];
+ ram_table->min_reduction[3][0] = min_reduction_table[abm_config[set][0]];
+ ram_table->min_reduction[4][0] = min_reduction_table[abm_config[set][0]];
+ ram_table->max_reduction[0][0] = max_reduction_table[abm_config[set][0]];
+ ram_table->max_reduction[1][0] = max_reduction_table[abm_config[set][0]];
+ ram_table->max_reduction[2][0] = max_reduction_table[abm_config[set][0]];
+ ram_table->max_reduction[3][0] = max_reduction_table[abm_config[set][0]];
+ ram_table->max_reduction[4][0] = max_reduction_table[abm_config[set][0]];
+
+ ram_table->min_reduction[0][1] = min_reduction_table[abm_config[set][1]];
+ ram_table->min_reduction[1][1] = min_reduction_table[abm_config[set][1]];
+ ram_table->min_reduction[2][1] = min_reduction_table[abm_config[set][1]];
+ ram_table->min_reduction[3][1] = min_reduction_table[abm_config[set][1]];
+ ram_table->min_reduction[4][1] = min_reduction_table[abm_config[set][1]];
+ ram_table->max_reduction[0][1] = max_reduction_table[abm_config[set][1]];
+ ram_table->max_reduction[1][1] = max_reduction_table[abm_config[set][1]];
+ ram_table->max_reduction[2][1] = max_reduction_table[abm_config[set][1]];
+ ram_table->max_reduction[3][1] = max_reduction_table[abm_config[set][1]];
+ ram_table->max_reduction[4][1] = max_reduction_table[abm_config[set][1]];
+
+ ram_table->min_reduction[0][2] = min_reduction_table[abm_config[set][2]];
+ ram_table->min_reduction[1][2] = min_reduction_table[abm_config[set][2]];
+ ram_table->min_reduction[2][2] = min_reduction_table[abm_config[set][2]];
+ ram_table->min_reduction[3][2] = min_reduction_table[abm_config[set][2]];
+ ram_table->min_reduction[4][2] = min_reduction_table[abm_config[set][2]];
+ ram_table->max_reduction[0][2] = max_reduction_table[abm_config[set][2]];
+ ram_table->max_reduction[1][2] = max_reduction_table[abm_config[set][2]];
+ ram_table->max_reduction[2][2] = max_reduction_table[abm_config[set][2]];
+ ram_table->max_reduction[3][2] = max_reduction_table[abm_config[set][2]];
+ ram_table->max_reduction[4][2] = max_reduction_table[abm_config[set][2]];
+
+ ram_table->min_reduction[0][3] = min_reduction_table[abm_config[set][3]];
+ ram_table->min_reduction[1][3] = min_reduction_table[abm_config[set][3]];
+ ram_table->min_reduction[2][3] = min_reduction_table[abm_config[set][3]];
+ ram_table->min_reduction[3][3] = min_reduction_table[abm_config[set][3]];
+ ram_table->min_reduction[4][3] = min_reduction_table[abm_config[set][3]];
+ ram_table->max_reduction[0][3] = max_reduction_table[abm_config[set][3]];
+ ram_table->max_reduction[1][3] = max_reduction_table[abm_config[set][3]];
+ ram_table->max_reduction[2][3] = max_reduction_table[abm_config[set][3]];
+ ram_table->max_reduction[3][3] = max_reduction_table[abm_config[set][3]];
+ ram_table->max_reduction[4][3] = max_reduction_table[abm_config[set][3]];
+
+ ram_table->bright_pos_gain[0][0] = 0x20;
+ ram_table->bright_pos_gain[0][1] = 0x20;
+ ram_table->bright_pos_gain[0][2] = 0x20;
+ ram_table->bright_pos_gain[0][3] = 0x20;
+ ram_table->bright_pos_gain[1][0] = 0x20;
+ ram_table->bright_pos_gain[1][1] = 0x20;
+ ram_table->bright_pos_gain[1][2] = 0x20;
+ ram_table->bright_pos_gain[1][3] = 0x20;
+ ram_table->bright_pos_gain[2][0] = 0x20;
+ ram_table->bright_pos_gain[2][1] = 0x20;
+ ram_table->bright_pos_gain[2][2] = 0x20;
+ ram_table->bright_pos_gain[2][3] = 0x20;
+ ram_table->bright_pos_gain[3][0] = 0x20;
+ ram_table->bright_pos_gain[3][1] = 0x20;
+ ram_table->bright_pos_gain[3][2] = 0x20;
+ ram_table->bright_pos_gain[3][3] = 0x20;
+ ram_table->bright_pos_gain[4][0] = 0x20;
+ ram_table->bright_pos_gain[4][1] = 0x20;
+ ram_table->bright_pos_gain[4][2] = 0x20;
+ ram_table->bright_pos_gain[4][3] = 0x20;
+ ram_table->bright_neg_gain[0][1] = 0x00;
+ ram_table->bright_neg_gain[0][2] = 0x00;
+ ram_table->bright_neg_gain[0][3] = 0x00;
+ ram_table->bright_neg_gain[1][0] = 0x00;
+ ram_table->bright_neg_gain[1][1] = 0x00;
+ ram_table->bright_neg_gain[1][2] = 0x00;
+ ram_table->bright_neg_gain[1][3] = 0x00;
+ ram_table->bright_neg_gain[2][0] = 0x00;
+ ram_table->bright_neg_gain[2][1] = 0x00;
+ ram_table->bright_neg_gain[2][2] = 0x00;
+ ram_table->bright_neg_gain[2][3] = 0x00;
+ ram_table->bright_neg_gain[3][0] = 0x00;
+ ram_table->bright_neg_gain[3][1] = 0x00;
+ ram_table->bright_neg_gain[3][2] = 0x00;
+ ram_table->bright_neg_gain[3][3] = 0x00;
+ ram_table->bright_neg_gain[4][0] = 0x00;
+ ram_table->bright_neg_gain[4][1] = 0x00;
+ ram_table->bright_neg_gain[4][2] = 0x00;
+ ram_table->bright_neg_gain[4][3] = 0x00;
+ ram_table->dark_pos_gain[0][0] = 0x00;
+ ram_table->dark_pos_gain[0][1] = 0x00;
+ ram_table->dark_pos_gain[0][2] = 0x00;
+ ram_table->dark_pos_gain[0][3] = 0x00;
+ ram_table->dark_pos_gain[1][0] = 0x00;
+ ram_table->dark_pos_gain[1][1] = 0x00;
+ ram_table->dark_pos_gain[1][2] = 0x00;
+ ram_table->dark_pos_gain[1][3] = 0x00;
+ ram_table->dark_pos_gain[2][0] = 0x00;
+ ram_table->dark_pos_gain[2][1] = 0x00;
+ ram_table->dark_pos_gain[2][2] = 0x00;
+ ram_table->dark_pos_gain[2][3] = 0x00;
+ ram_table->dark_pos_gain[3][0] = 0x00;
+ ram_table->dark_pos_gain[3][1] = 0x00;
+ ram_table->dark_pos_gain[3][2] = 0x00;
+ ram_table->dark_pos_gain[3][3] = 0x00;
+ ram_table->dark_pos_gain[4][0] = 0x00;
+ ram_table->dark_pos_gain[4][1] = 0x00;
+ ram_table->dark_pos_gain[4][2] = 0x00;
+ ram_table->dark_pos_gain[4][3] = 0x00;
+ ram_table->dark_neg_gain[0][0] = 0x00;
+ ram_table->dark_neg_gain[0][1] = 0x00;
+ ram_table->dark_neg_gain[0][2] = 0x00;
+ ram_table->dark_neg_gain[0][3] = 0x00;
+ ram_table->dark_neg_gain[1][0] = 0x00;
+ ram_table->dark_neg_gain[1][1] = 0x00;
+ ram_table->dark_neg_gain[1][2] = 0x00;
+ ram_table->dark_neg_gain[1][3] = 0x00;
+ ram_table->dark_neg_gain[2][0] = 0x00;
+ ram_table->dark_neg_gain[2][1] = 0x00;
+ ram_table->dark_neg_gain[2][2] = 0x00;
+ ram_table->dark_neg_gain[2][3] = 0x00;
+ ram_table->dark_neg_gain[3][0] = 0x00;
+ ram_table->dark_neg_gain[3][1] = 0x00;
+ ram_table->dark_neg_gain[3][2] = 0x00;
+ ram_table->dark_neg_gain[3][3] = 0x00;
+ ram_table->dark_neg_gain[4][0] = 0x00;
+ ram_table->dark_neg_gain[4][1] = 0x00;
+ ram_table->dark_neg_gain[4][2] = 0x00;
+ ram_table->dark_neg_gain[4][3] = 0x00;
+
+ ram_table->iir_curve[0] = 0x65;
+ ram_table->iir_curve[1] = 0x65;
+ ram_table->iir_curve[2] = 0x65;
+ ram_table->iir_curve[3] = 0x65;
+ ram_table->iir_curve[4] = 0x65;
+
+ //Gamma 2.4
+ ram_table->crgb_thresh[0] = cpu_to_be16(0x13b6);
+ ram_table->crgb_thresh[1] = cpu_to_be16(0x1648);
+ ram_table->crgb_thresh[2] = cpu_to_be16(0x18e3);
+ ram_table->crgb_thresh[3] = cpu_to_be16(0x1b41);
+ ram_table->crgb_thresh[4] = cpu_to_be16(0x1d46);
+ ram_table->crgb_thresh[5] = cpu_to_be16(0x1f21);
+ ram_table->crgb_thresh[6] = cpu_to_be16(0x2167);
+ ram_table->crgb_thresh[7] = cpu_to_be16(0x2384);
+ ram_table->crgb_offset[0] = cpu_to_be16(0x2999);
+ ram_table->crgb_offset[1] = cpu_to_be16(0x3999);
+ ram_table->crgb_offset[2] = cpu_to_be16(0x4666);
+ ram_table->crgb_offset[3] = cpu_to_be16(0x5999);
+ ram_table->crgb_offset[4] = cpu_to_be16(0x6333);
+ ram_table->crgb_offset[5] = cpu_to_be16(0x7800);
+ ram_table->crgb_offset[6] = cpu_to_be16(0x8c00);
+ ram_table->crgb_offset[7] = cpu_to_be16(0xa000);
+ ram_table->crgb_slope[0] = cpu_to_be16(0x3147);
+ ram_table->crgb_slope[1] = cpu_to_be16(0x2978);
+ ram_table->crgb_slope[2] = cpu_to_be16(0x23a2);
+ ram_table->crgb_slope[3] = cpu_to_be16(0x1f55);
+ ram_table->crgb_slope[4] = cpu_to_be16(0x1c63);
+ ram_table->crgb_slope[5] = cpu_to_be16(0x1a0f);
+ ram_table->crgb_slope[6] = cpu_to_be16(0x178d);
+ ram_table->crgb_slope[7] = cpu_to_be16(0x15ab);
+
+ fill_backlight_transform_table(
+ params, ram_table);
+}
+
+void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params)
+{
+ unsigned int set = params.set;
+
+ ram_table->flags = 0x0;
+
+ ram_table->deviation_gain[0] = 0xb3;
+ ram_table->deviation_gain[1] = 0xb3;
+ ram_table->deviation_gain[2] = 0xb3;
+ ram_table->deviation_gain[3] = 0xb3;
+
+ ram_table->min_reduction[0][0] = min_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->min_reduction[1][0] = min_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->min_reduction[2][0] = min_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->min_reduction[3][0] = min_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->min_reduction[4][0] = min_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->max_reduction[0][0] = max_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->max_reduction[1][0] = max_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->max_reduction[2][0] = max_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->max_reduction[3][0] = max_reduction_table_v_2_2[abm_config[set][0]];
+ ram_table->max_reduction[4][0] = max_reduction_table_v_2_2[abm_config[set][0]];
+
+ ram_table->min_reduction[0][1] = min_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->min_reduction[1][1] = min_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->min_reduction[2][1] = min_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->min_reduction[3][1] = min_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->min_reduction[4][1] = min_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->max_reduction[0][1] = max_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->max_reduction[1][1] = max_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->max_reduction[2][1] = max_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->max_reduction[3][1] = max_reduction_table_v_2_2[abm_config[set][1]];
+ ram_table->max_reduction[4][1] = max_reduction_table_v_2_2[abm_config[set][1]];
+
+ ram_table->min_reduction[0][2] = min_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->min_reduction[1][2] = min_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->min_reduction[2][2] = min_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->min_reduction[3][2] = min_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->min_reduction[4][2] = min_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->max_reduction[0][2] = max_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->max_reduction[1][2] = max_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->max_reduction[2][2] = max_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->max_reduction[3][2] = max_reduction_table_v_2_2[abm_config[set][2]];
+ ram_table->max_reduction[4][2] = max_reduction_table_v_2_2[abm_config[set][2]];
+
+ ram_table->min_reduction[0][3] = min_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->min_reduction[1][3] = min_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->min_reduction[2][3] = min_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->min_reduction[3][3] = min_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->min_reduction[4][3] = min_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->max_reduction[0][3] = max_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->max_reduction[1][3] = max_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->max_reduction[2][3] = max_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->max_reduction[3][3] = max_reduction_table_v_2_2[abm_config[set][3]];
+ ram_table->max_reduction[4][3] = max_reduction_table_v_2_2[abm_config[set][3]];
+
+ ram_table->bright_pos_gain[0][0] = 0x20;
+ ram_table->bright_pos_gain[0][1] = 0x20;
+ ram_table->bright_pos_gain[0][2] = 0x20;
+ ram_table->bright_pos_gain[0][3] = 0x20;
+ ram_table->bright_pos_gain[1][0] = 0x20;
+ ram_table->bright_pos_gain[1][1] = 0x20;
+ ram_table->bright_pos_gain[1][2] = 0x20;
+ ram_table->bright_pos_gain[1][3] = 0x20;
+ ram_table->bright_pos_gain[2][0] = 0x20;
+ ram_table->bright_pos_gain[2][1] = 0x20;
+ ram_table->bright_pos_gain[2][2] = 0x20;
+ ram_table->bright_pos_gain[2][3] = 0x20;
+ ram_table->bright_pos_gain[3][0] = 0x20;
+ ram_table->bright_pos_gain[3][1] = 0x20;
+ ram_table->bright_pos_gain[3][2] = 0x20;
+ ram_table->bright_pos_gain[3][3] = 0x20;
+ ram_table->bright_pos_gain[4][0] = 0x20;
+ ram_table->bright_pos_gain[4][1] = 0x20;
+ ram_table->bright_pos_gain[4][2] = 0x20;
+ ram_table->bright_pos_gain[4][3] = 0x20;
+
+ ram_table->dark_pos_gain[0][0] = 0x00;
+ ram_table->dark_pos_gain[0][1] = 0x00;
+ ram_table->dark_pos_gain[0][2] = 0x00;
+ ram_table->dark_pos_gain[0][3] = 0x00;
+ ram_table->dark_pos_gain[1][0] = 0x00;
+ ram_table->dark_pos_gain[1][1] = 0x00;
+ ram_table->dark_pos_gain[1][2] = 0x00;
+ ram_table->dark_pos_gain[1][3] = 0x00;
+ ram_table->dark_pos_gain[2][0] = 0x00;
+ ram_table->dark_pos_gain[2][1] = 0x00;
+ ram_table->dark_pos_gain[2][2] = 0x00;
+ ram_table->dark_pos_gain[2][3] = 0x00;
+ ram_table->dark_pos_gain[3][0] = 0x00;
+ ram_table->dark_pos_gain[3][1] = 0x00;
+ ram_table->dark_pos_gain[3][2] = 0x00;
+ ram_table->dark_pos_gain[3][3] = 0x00;
+ ram_table->dark_pos_gain[4][0] = 0x00;
+ ram_table->dark_pos_gain[4][1] = 0x00;
+ ram_table->dark_pos_gain[4][2] = 0x00;
+ ram_table->dark_pos_gain[4][3] = 0x00;
+
+ ram_table->hybridFactor[0] = 0xff;
+ ram_table->hybridFactor[1] = 0xff;
+ ram_table->hybridFactor[2] = 0xff;
+ ram_table->hybridFactor[3] = 0xc0;
+
+ ram_table->contrastFactor[0] = 0x99;
+ ram_table->contrastFactor[1] = 0x99;
+ ram_table->contrastFactor[2] = 0x99;
+ ram_table->contrastFactor[3] = 0x80;
+
+ ram_table->iir_curve[0] = 0x65;
+ ram_table->iir_curve[1] = 0x65;
+ ram_table->iir_curve[2] = 0x65;
+ ram_table->iir_curve[3] = 0x65;
+ ram_table->iir_curve[4] = 0x65;
+
+ //Gamma 2.2
+ ram_table->crgb_thresh[0] = cpu_to_be16(0x127c);
+ ram_table->crgb_thresh[1] = cpu_to_be16(0x151b);
+ ram_table->crgb_thresh[2] = cpu_to_be16(0x17d5);
+ ram_table->crgb_thresh[3] = cpu_to_be16(0x1a56);
+ ram_table->crgb_thresh[4] = cpu_to_be16(0x1c83);
+ ram_table->crgb_thresh[5] = cpu_to_be16(0x1e72);
+ ram_table->crgb_thresh[6] = cpu_to_be16(0x20f0);
+ ram_table->crgb_thresh[7] = cpu_to_be16(0x232b);
+ ram_table->crgb_offset[0] = cpu_to_be16(0x2999);
+ ram_table->crgb_offset[1] = cpu_to_be16(0x3999);
+ ram_table->crgb_offset[2] = cpu_to_be16(0x4666);
+ ram_table->crgb_offset[3] = cpu_to_be16(0x5999);
+ ram_table->crgb_offset[4] = cpu_to_be16(0x6333);
+ ram_table->crgb_offset[5] = cpu_to_be16(0x7800);
+ ram_table->crgb_offset[6] = cpu_to_be16(0x8c00);
+ ram_table->crgb_offset[7] = cpu_to_be16(0xa000);
+ ram_table->crgb_slope[0] = cpu_to_be16(0x3609);
+ ram_table->crgb_slope[1] = cpu_to_be16(0x2dfa);
+ ram_table->crgb_slope[2] = cpu_to_be16(0x27ea);
+ ram_table->crgb_slope[3] = cpu_to_be16(0x235d);
+ ram_table->crgb_slope[4] = cpu_to_be16(0x2042);
+ ram_table->crgb_slope[5] = cpu_to_be16(0x1dc3);
+ ram_table->crgb_slope[6] = cpu_to_be16(0x1b1a);
+ ram_table->crgb_slope[7] = cpu_to_be16(0x1910);
+
+ fill_backlight_transform_table_v_2_2(
+ params, ram_table);
+}
+
bool dmcu_load_iram(struct dmcu *dmcu,
struct dmcu_iram_parameters params)
{
- struct iram_table_v_2 ram_table;
- unsigned int set = params.set;
+ unsigned char ram_table[IRAM_SIZE];
+ bool result = false;
if (dmcu == NULL)
return false;
@@ -157,170 +573,23 @@ bool dmcu_load_iram(struct dmcu *dmcu,
memset(&ram_table, 0, sizeof(ram_table));
- ram_table.flags = 0x0;
- ram_table.deviation_gain = 0xb3;
+ if (dmcu->dmcu_version.abm_version == 0x22) {
+ fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params);
- ram_table.blRampReduction =
- cpu_to_be16(params.backlight_ramping_reduction);
- ram_table.blRampStart =
- cpu_to_be16(params.backlight_ramping_start);
+ result = dmcu->funcs->load_iram(
+ dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2);
+ } else {
+ fill_iram_v_2((struct iram_table_v_2 *)ram_table, params);
- ram_table.min_reduction[0][0] = min_reduction_table[abm_config[set][0]];
- ram_table.min_reduction[1][0] = min_reduction_table[abm_config[set][0]];
- ram_table.min_reduction[2][0] = min_reduction_table[abm_config[set][0]];
- ram_table.min_reduction[3][0] = min_reduction_table[abm_config[set][0]];
- ram_table.min_reduction[4][0] = min_reduction_table[abm_config[set][0]];
- ram_table.max_reduction[0][0] = max_reduction_table[abm_config[set][0]];
- ram_table.max_reduction[1][0] = max_reduction_table[abm_config[set][0]];
- ram_table.max_reduction[2][0] = max_reduction_table[abm_config[set][0]];
- ram_table.max_reduction[3][0] = max_reduction_table[abm_config[set][0]];
- ram_table.max_reduction[4][0] = max_reduction_table[abm_config[set][0]];
-
- ram_table.min_reduction[0][1] = min_reduction_table[abm_config[set][1]];
- ram_table.min_reduction[1][1] = min_reduction_table[abm_config[set][1]];
- ram_table.min_reduction[2][1] = min_reduction_table[abm_config[set][1]];
- ram_table.min_reduction[3][1] = min_reduction_table[abm_config[set][1]];
- ram_table.min_reduction[4][1] = min_reduction_table[abm_config[set][1]];
- ram_table.max_reduction[0][1] = max_reduction_table[abm_config[set][1]];
- ram_table.max_reduction[1][1] = max_reduction_table[abm_config[set][1]];
- ram_table.max_reduction[2][1] = max_reduction_table[abm_config[set][1]];
- ram_table.max_reduction[3][1] = max_reduction_table[abm_config[set][1]];
- ram_table.max_reduction[4][1] = max_reduction_table[abm_config[set][1]];
-
- ram_table.min_reduction[0][2] = min_reduction_table[abm_config[set][2]];
- ram_table.min_reduction[1][2] = min_reduction_table[abm_config[set][2]];
- ram_table.min_reduction[2][2] = min_reduction_table[abm_config[set][2]];
- ram_table.min_reduction[3][2] = min_reduction_table[abm_config[set][2]];
- ram_table.min_reduction[4][2] = min_reduction_table[abm_config[set][2]];
- ram_table.max_reduction[0][2] = max_reduction_table[abm_config[set][2]];
- ram_table.max_reduction[1][2] = max_reduction_table[abm_config[set][2]];
- ram_table.max_reduction[2][2] = max_reduction_table[abm_config[set][2]];
- ram_table.max_reduction[3][2] = max_reduction_table[abm_config[set][2]];
- ram_table.max_reduction[4][2] = max_reduction_table[abm_config[set][2]];
-
- ram_table.min_reduction[0][3] = min_reduction_table[abm_config[set][3]];
- ram_table.min_reduction[1][3] = min_reduction_table[abm_config[set][3]];
- ram_table.min_reduction[2][3] = min_reduction_table[abm_config[set][3]];
- ram_table.min_reduction[3][3] = min_reduction_table[abm_config[set][3]];
- ram_table.min_reduction[4][3] = min_reduction_table[abm_config[set][3]];
- ram_table.max_reduction[0][3] = max_reduction_table[abm_config[set][3]];
- ram_table.max_reduction[1][3] = max_reduction_table[abm_config[set][3]];
- ram_table.max_reduction[2][3] = max_reduction_table[abm_config[set][3]];
- ram_table.max_reduction[3][3] = max_reduction_table[abm_config[set][3]];
- ram_table.max_reduction[4][3] = max_reduction_table[abm_config[set][3]];
-
- ram_table.bright_pos_gain[0][0] = 0x20;
- ram_table.bright_pos_gain[0][1] = 0x20;
- ram_table.bright_pos_gain[0][2] = 0x20;
- ram_table.bright_pos_gain[0][3] = 0x20;
- ram_table.bright_pos_gain[1][0] = 0x20;
- ram_table.bright_pos_gain[1][1] = 0x20;
- ram_table.bright_pos_gain[1][2] = 0x20;
- ram_table.bright_pos_gain[1][3] = 0x20;
- ram_table.bright_pos_gain[2][0] = 0x20;
- ram_table.bright_pos_gain[2][1] = 0x20;
- ram_table.bright_pos_gain[2][2] = 0x20;
- ram_table.bright_pos_gain[2][3] = 0x20;
- ram_table.bright_pos_gain[3][0] = 0x20;
- ram_table.bright_pos_gain[3][1] = 0x20;
- ram_table.bright_pos_gain[3][2] = 0x20;
- ram_table.bright_pos_gain[3][3] = 0x20;
- ram_table.bright_pos_gain[4][0] = 0x20;
- ram_table.bright_pos_gain[4][1] = 0x20;
- ram_table.bright_pos_gain[4][2] = 0x20;
- ram_table.bright_pos_gain[4][3] = 0x20;
- ram_table.bright_neg_gain[0][1] = 0x00;
- ram_table.bright_neg_gain[0][2] = 0x00;
- ram_table.bright_neg_gain[0][3] = 0x00;
- ram_table.bright_neg_gain[1][0] = 0x00;
- ram_table.bright_neg_gain[1][1] = 0x00;
- ram_table.bright_neg_gain[1][2] = 0x00;
- ram_table.bright_neg_gain[1][3] = 0x00;
- ram_table.bright_neg_gain[2][0] = 0x00;
- ram_table.bright_neg_gain[2][1] = 0x00;
- ram_table.bright_neg_gain[2][2] = 0x00;
- ram_table.bright_neg_gain[2][3] = 0x00;
- ram_table.bright_neg_gain[3][0] = 0x00;
- ram_table.bright_neg_gain[3][1] = 0x00;
- ram_table.bright_neg_gain[3][2] = 0x00;
- ram_table.bright_neg_gain[3][3] = 0x00;
- ram_table.bright_neg_gain[4][0] = 0x00;
- ram_table.bright_neg_gain[4][1] = 0x00;
- ram_table.bright_neg_gain[4][2] = 0x00;
- ram_table.bright_neg_gain[4][3] = 0x00;
- ram_table.dark_pos_gain[0][0] = 0x00;
- ram_table.dark_pos_gain[0][1] = 0x00;
- ram_table.dark_pos_gain[0][2] = 0x00;
- ram_table.dark_pos_gain[0][3] = 0x00;
- ram_table.dark_pos_gain[1][0] = 0x00;
- ram_table.dark_pos_gain[1][1] = 0x00;
- ram_table.dark_pos_gain[1][2] = 0x00;
- ram_table.dark_pos_gain[1][3] = 0x00;
- ram_table.dark_pos_gain[2][0] = 0x00;
- ram_table.dark_pos_gain[2][1] = 0x00;
- ram_table.dark_pos_gain[2][2] = 0x00;
- ram_table.dark_pos_gain[2][3] = 0x00;
- ram_table.dark_pos_gain[3][0] = 0x00;
- ram_table.dark_pos_gain[3][1] = 0x00;
- ram_table.dark_pos_gain[3][2] = 0x00;
- ram_table.dark_pos_gain[3][3] = 0x00;
- ram_table.dark_pos_gain[4][0] = 0x00;
- ram_table.dark_pos_gain[4][1] = 0x00;
- ram_table.dark_pos_gain[4][2] = 0x00;
- ram_table.dark_pos_gain[4][3] = 0x00;
- ram_table.dark_neg_gain[0][0] = 0x00;
- ram_table.dark_neg_gain[0][1] = 0x00;
- ram_table.dark_neg_gain[0][2] = 0x00;
- ram_table.dark_neg_gain[0][3] = 0x00;
- ram_table.dark_neg_gain[1][0] = 0x00;
- ram_table.dark_neg_gain[1][1] = 0x00;
- ram_table.dark_neg_gain[1][2] = 0x00;
- ram_table.dark_neg_gain[1][3] = 0x00;
- ram_table.dark_neg_gain[2][0] = 0x00;
- ram_table.dark_neg_gain[2][1] = 0x00;
- ram_table.dark_neg_gain[2][2] = 0x00;
- ram_table.dark_neg_gain[2][3] = 0x00;
- ram_table.dark_neg_gain[3][0] = 0x00;
- ram_table.dark_neg_gain[3][1] = 0x00;
- ram_table.dark_neg_gain[3][2] = 0x00;
- ram_table.dark_neg_gain[3][3] = 0x00;
- ram_table.dark_neg_gain[4][0] = 0x00;
- ram_table.dark_neg_gain[4][1] = 0x00;
- ram_table.dark_neg_gain[4][2] = 0x00;
- ram_table.dark_neg_gain[4][3] = 0x00;
- ram_table.iir_curve[0] = 0x65;
- ram_table.iir_curve[1] = 0x65;
- ram_table.iir_curve[2] = 0x65;
- ram_table.iir_curve[3] = 0x65;
- ram_table.iir_curve[4] = 0x65;
- ram_table.crgb_thresh[0] = cpu_to_be16(0x13b6);
- ram_table.crgb_thresh[1] = cpu_to_be16(0x1648);
- ram_table.crgb_thresh[2] = cpu_to_be16(0x18e3);
- ram_table.crgb_thresh[3] = cpu_to_be16(0x1b41);
- ram_table.crgb_thresh[4] = cpu_to_be16(0x1d46);
- ram_table.crgb_thresh[5] = cpu_to_be16(0x1f21);
- ram_table.crgb_thresh[6] = cpu_to_be16(0x2167);
- ram_table.crgb_thresh[7] = cpu_to_be16(0x2384);
- ram_table.crgb_offset[0] = cpu_to_be16(0x2999);
- ram_table.crgb_offset[1] = cpu_to_be16(0x3999);
- ram_table.crgb_offset[2] = cpu_to_be16(0x4666);
- ram_table.crgb_offset[3] = cpu_to_be16(0x5999);
- ram_table.crgb_offset[4] = cpu_to_be16(0x6333);
- ram_table.crgb_offset[5] = cpu_to_be16(0x7800);
- ram_table.crgb_offset[6] = cpu_to_be16(0x8c00);
- ram_table.crgb_offset[7] = cpu_to_be16(0xa000);
- ram_table.crgb_slope[0] = cpu_to_be16(0x3147);
- ram_table.crgb_slope[1] = cpu_to_be16(0x2978);
- ram_table.crgb_slope[2] = cpu_to_be16(0x23a2);
- ram_table.crgb_slope[3] = cpu_to_be16(0x1f55);
- ram_table.crgb_slope[4] = cpu_to_be16(0x1c63);
- ram_table.crgb_slope[5] = cpu_to_be16(0x1a0f);
- ram_table.crgb_slope[6] = cpu_to_be16(0x178d);
- ram_table.crgb_slope[7] = cpu_to_be16(0x15ab);
+ result = dmcu->funcs->load_iram(
+ dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2);
- fill_backlight_transform_table(
- params, &ram_table);
+ if (result)
+ result = dmcu->funcs->load_iram(
+ dmcu, IRAM_RESERVE_AREA_END_V2 + 1,
+ (char *)(&ram_table) + IRAM_RESERVE_AREA_END_V2 + 1,
+ sizeof(ram_table) - IRAM_RESERVE_AREA_END_V2 - 1);
+ }
- return dmcu->funcs->load_iram(
- dmcu, 0, (char *)(&ram_table), sizeof(ram_table));
+ return result;
}
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_offset.h
index 13d4de645190..d8e0dd192fdd 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_offset.h
@@ -2247,6 +2247,8 @@
// addressBlock: nbio_nbif_rcc_strap_BIFDEC1[13440..14975]
// base address: 0x3480
+#define mmRCC_BIF_STRAP0 0x0000
+#define mmRCC_BIF_STRAP0_BASE_IDX 2
#define mmRCC_DEV0_EPF0_STRAP0 0x000f
#define mmRCC_DEV0_EPF0_STRAP0_BASE_IDX 2
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_sh_mask.h
index a02b67943372..29af5167cd00 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_sh_mask.h
@@ -16838,6 +16838,10 @@
// addressBlock: nbio_nbif_rcc_strap_BIFDEC1[13440..14975]
+//RCC_BIF_STRAP0
+#define RCC_BIF_STRAP0__STRAP_PX_CAPABLE__SHIFT 0x7
+#define RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK 0x00000080L
+
//RCC_DEV0_EPF0_STRAP0
#define RCC_DEV0_EPF0_STRAP0__STRAP_DEVICE_ID_DEV0_F0__SHIFT 0x0
#define RCC_DEV0_EPF0_STRAP0__STRAP_MAJOR_REV_ID_DEV0_F0__SHIFT 0x10
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_smn.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_smn.h
new file mode 100644
index 000000000000..8c75669eb500
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_6_1_smn.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _nbio_6_1_SMN_HEADER
+#define _nbio_6_1_SMN_HEADER
+
+
+#define smnCPM_CONTROL 0x11180460
+#define smnPCIE_CNTL2 0x11180070
+#define smnPCIE_CONFIG_CNTL 0x11180044
+#define smnPCIE_CI_CNTL 0x11180080
+
+
+#define smnPCIE_PERF_COUNT_CNTL 0x11180200
+#define smnPCIE_PERF_CNTL_TXCLK 0x11180204
+#define smnPCIE_PERF_COUNT0_TXCLK 0x11180208
+#define smnPCIE_PERF_COUNT1_TXCLK 0x1118020c
+#define smnPCIE_PERF_CNTL_MST_R_CLK 0x11180210
+#define smnPCIE_PERF_COUNT0_MST_R_CLK 0x11180214
+#define smnPCIE_PERF_COUNT1_MST_R_CLK 0x11180218
+#define smnPCIE_PERF_CNTL_MST_C_CLK 0x1118021c
+#define smnPCIE_PERF_COUNT0_MST_C_CLK 0x11180220
+#define smnPCIE_PERF_COUNT1_MST_C_CLK 0x11180224
+#define smnPCIE_PERF_CNTL_SLV_R_CLK 0x11180228
+#define smnPCIE_PERF_COUNT0_SLV_R_CLK 0x1118022c
+#define smnPCIE_PERF_COUNT1_SLV_R_CLK 0x11180230
+#define smnPCIE_PERF_CNTL_SLV_S_C_CLK 0x11180234
+#define smnPCIE_PERF_COUNT0_SLV_S_C_CLK 0x11180238
+#define smnPCIE_PERF_COUNT1_SLV_S_C_CLK 0x1118023c
+#define smnPCIE_PERF_CNTL_SLV_NS_C_CLK 0x11180240
+#define smnPCIE_PERF_COUNT0_SLV_NS_C_CLK 0x11180244
+#define smnPCIE_PERF_COUNT1_SLV_NS_C_CLK 0x11180248
+#define smnPCIE_PERF_CNTL_EVENT0_PORT_SEL 0x1118024c
+#define smnPCIE_PERF_CNTL_EVENT1_PORT_SEL 0x11180250
+#define smnPCIE_PERF_CNTL_TXCLK2 0x11180254
+#define smnPCIE_PERF_COUNT0_TXCLK2 0x11180258
+#define smnPCIE_PERF_COUNT1_TXCLK2 0x1118025c
+
+#endif // _nbio_6_1_SMN_HEADER
+
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_0_smn.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_0_smn.h
new file mode 100644
index 000000000000..5563f0715896
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_0_smn.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _nbio_7_0_SMN_HEADER
+#define _nbio_7_0_SMN_HEADER
+
+
+#define smnCPM_CONTROL 0x11180460
+#define smnPCIE_CNTL2 0x11180070
+
+#define smnPCIE_PERF_COUNT_CNTL 0x11180200
+#define smnPCIE_PERF_CNTL_TXCLK 0x11180204
+#define smnPCIE_PERF_COUNT0_TXCLK 0x11180208
+#define smnPCIE_PERF_COUNT1_TXCLK 0x1118020c
+#define smnPCIE_PERF_CNTL_MST_R_CLK 0x11180210
+#define smnPCIE_PERF_COUNT0_MST_R_CLK 0x11180214
+#define smnPCIE_PERF_COUNT1_MST_R_CLK 0x11180218
+#define smnPCIE_PERF_CNTL_MST_C_CLK 0x1118021c
+#define smnPCIE_PERF_COUNT0_MST_C_CLK 0x11180220
+#define smnPCIE_PERF_COUNT1_MST_C_CLK 0x11180224
+#define smnPCIE_PERF_CNTL_SLV_R_CLK 0x11180228
+#define smnPCIE_PERF_COUNT0_SLV_R_CLK 0x1118022c
+#define smnPCIE_PERF_COUNT1_SLV_R_CLK 0x11180230
+#define smnPCIE_PERF_CNTL_SLV_S_C_CLK 0x11180234
+#define smnPCIE_PERF_COUNT0_SLV_S_C_CLK 0x11180238
+#define smnPCIE_PERF_COUNT1_SLV_S_C_CLK 0x1118023c
+#define smnPCIE_PERF_CNTL_SLV_NS_C_CLK 0x11180240
+#define smnPCIE_PERF_COUNT0_SLV_NS_C_CLK 0x11180244
+#define smnPCIE_PERF_COUNT1_SLV_NS_C_CLK 0x11180248
+#define smnPCIE_PERF_CNTL_EVENT0_PORT_SEL 0x1118024c
+#define smnPCIE_PERF_CNTL_EVENT1_PORT_SEL 0x11180250
+#define smnPCIE_PERF_CNTL_TXCLK2 0x11180254
+#define smnPCIE_PERF_COUNT0_TXCLK2 0x11180258
+#define smnPCIE_PERF_COUNT1_TXCLK2 0x1118025c
+
+#endif // _nbio_7_0_SMN_HEADER
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_0_smn.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_0_smn.h
new file mode 100644
index 000000000000..c1457d880c4d
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_0_smn.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _nbio_7_4_0_SMN_HEADER
+#define _nbio_7_4_0_SMN_HEADER
+
+
+#define smnNBIF_MGCG_CTRL_LCLK 0x1013a21c
+#define smnCPM_CONTROL 0x11180460
+#define smnPCIE_CNTL2 0x11180070
+#define smnPCIE_CI_CNTL 0x11180080
+
+#define smnPCIE_PERF_COUNT_CNTL 0x11180200
+#define smnPCIE_PERF_CNTL_TXCLK1 0x11180204
+#define smnPCIE_PERF_COUNT0_TXCLK1 0x11180208
+#define smnPCIE_PERF_COUNT1_TXCLK1 0x1118020c
+#define smnPCIE_PERF_CNTL_TXCLK2 0x11180210
+#define smnPCIE_PERF_COUNT0_TXCLK2 0x11180214
+#define smnPCIE_PERF_COUNT1_TXCLK2 0x11180218
+#define smnPCIE_PERF_CNTL_TXCLK3 0x1118021c
+#define smnPCIE_PERF_COUNT0_TXCLK3 0x11180220
+#define smnPCIE_PERF_COUNT1_TXCLK3 0x11180224
+#define smnPCIE_PERF_CNTL_TXCLK4 0x11180228
+#define smnPCIE_PERF_COUNT0_TXCLK4 0x1118022c
+#define smnPCIE_PERF_COUNT1_TXCLK4 0x11180230
+#define smnPCIE_PERF_CNTL_SCLK1 0x11180234
+#define smnPCIE_PERF_COUNT0_SCLK1 0x11180238
+#define smnPCIE_PERF_COUNT1_SCLK1 0x1118023c
+#define smnPCIE_PERF_CNTL_SCLK2 0x11180240
+#define smnPCIE_PERF_COUNT0_SCLK2 0x11180244
+#define smnPCIE_PERF_COUNT1_SCLK2 0x11180248
+#define smnPCIE_PERF_CNTL_EVENT_LC_PORT_SEL 0x1118024c
+#define smnPCIE_PERF_CNTL_EVENT_CI_PORT_SEL 0x11180250
+
+#endif // _nbio_7_4_0_SMN_HEADER
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_offset.h
index e932213f87f0..994e796a28d7 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_offset.h
@@ -2567,6 +2567,8 @@
// addressBlock: nbio_nbif0_rcc_strap_BIFDEC1
// base address: 0x0
+#define mmRCC_BIF_STRAP0 0x0000
+#define mmRCC_BIF_STRAP0_BASE_IDX 2
#define mmRCC_DEV0_EPF0_STRAP0 0x0011
#define mmRCC_DEV0_EPF0_STRAP0_BASE_IDX 2
diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_sh_mask.h
index d3704b438f2d..d467b939c971 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_4_sh_mask.h
@@ -19690,6 +19690,9 @@
// addressBlock: nbio_nbif0_rcc_strap_BIFDEC1
+//RCC_BIF_STRAP0
+#define RCC_BIF_STRAP0__STRAP_PX_CAPABLE__SHIFT 0x7
+#define RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK 0x00000080L
//RCC_DEV0_EPF0_STRAP0
#define RCC_DEV0_EPF0_STRAP0__STRAP_DEVICE_ID_DEV0_F0__SHIFT 0x0
#define RCC_DEV0_EPF0_STRAP0__STRAP_MAJOR_REV_ID_DEV0_F0__SHIFT 0x10
diff --git a/drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h b/drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h
index a9eb57a53e59..a485526f3a51 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h
@@ -46,4 +46,7 @@
#define mmTHM_TCON_THERM_TRIP 0x0002
#define mmTHM_TCON_THERM_TRIP_BASE_IDX 0
+#define mmTHM_BACO_CNTL 0x0081
+#define mmTHM_BACO_CNTL_BASE_IDX 0
+
#endif
diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h
index 7931502fa54f..8ba21747b40a 100644
--- a/drivers/gpu/drm/amd/include/atombios.h
+++ b/drivers/gpu/drm/amd/include/atombios.h
@@ -4106,7 +4106,7 @@ typedef struct _ATOM_LCD_MODE_CONTROL_CAP
typedef struct _ATOM_FAKE_EDID_PATCH_RECORD
{
UCHAR ucRecordType;
- UCHAR ucFakeEDIDLength; // = 128 means EDID lenght is 128 bytes, otherwise the EDID length = ucFakeEDIDLength*128
+ UCHAR ucFakeEDIDLength; // = 128 means EDID length is 128 bytes, otherwise the EDID length = ucFakeEDIDLength*128
UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements.
} ATOM_FAKE_EDID_PATCH_RECORD;
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 8154d67388cc..83d960110d23 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -34,7 +34,6 @@
struct pci_dev;
-#define KFD_INTERFACE_VERSION 2
#define KGD_MAX_QUEUES 128
struct kfd_dev;
@@ -330,56 +329,4 @@ struct kfd2kgd_calls {
};
-/**
- * struct kgd2kfd_calls
- *
- * @exit: Notifies amdkfd that kgd module is unloaded
- *
- * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
- *
- * @device_init: Initialize the newly probed device (if it is a device that
- * amdkfd supports)
- *
- * @device_exit: Notifies amdkfd about a removal of a kgd device
- *
- * @suspend: Notifies amdkfd about a suspend action done to a kgd device
- *
- * @resume: Notifies amdkfd about a resume action done to a kgd device
- *
- * @quiesce_mm: Quiesce all user queue access to specified MM address space
- *
- * @resume_mm: Resume user queue access to specified MM address space
- *
- * @schedule_evict_and_restore_process: Schedules work queue that will prepare
- * for safe eviction of KFD BOs that belong to the specified process.
- *
- * @pre_reset: Notifies amdkfd that amdgpu about to reset the gpu
- *
- * @post_reset: Notify amdkfd that amgpu successfully reseted the gpu
- *
- * This structure contains function callback pointers so the kgd driver
- * will notify to the amdkfd about certain status changes.
- *
- */
-struct kgd2kfd_calls {
- void (*exit)(void);
- struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev,
- const struct kfd2kgd_calls *f2g);
- bool (*device_init)(struct kfd_dev *kfd,
- const struct kgd2kfd_shared_resources *gpu_resources);
- void (*device_exit)(struct kfd_dev *kfd);
- void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
- void (*suspend)(struct kfd_dev *kfd);
- int (*resume)(struct kfd_dev *kfd);
- int (*quiesce_mm)(struct mm_struct *mm);
- int (*resume_mm)(struct mm_struct *mm);
- int (*schedule_evict_and_restore_process)(struct mm_struct *mm,
- struct dma_fence *fence);
- int (*pre_reset)(struct kfd_dev *kfd);
- int (*post_reset)(struct kfd_dev *kfd);
-};
-
-int kgd2kfd_init(unsigned interface_version,
- const struct kgd2kfd_calls **g2f);
-
#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index 1479ea1dc3e7..2b579ba9b685 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -92,6 +92,9 @@ enum pp_clock_type {
PP_SCLK,
PP_MCLK,
PP_PCIE,
+ PP_SOCCLK,
+ PP_FCLK,
+ PP_DCEFCLK,
OD_SCLK,
OD_MCLK,
OD_VDDC_CURVE,
@@ -127,12 +130,13 @@ enum amd_pp_task {
};
enum PP_SMC_POWER_PROFILE {
- PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x0,
- PP_SMC_POWER_PROFILE_POWERSAVING = 0x1,
- PP_SMC_POWER_PROFILE_VIDEO = 0x2,
- PP_SMC_POWER_PROFILE_VR = 0x3,
- PP_SMC_POWER_PROFILE_COMPUTE = 0x4,
- PP_SMC_POWER_PROFILE_CUSTOM = 0x5,
+ PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0,
+ PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1,
+ PP_SMC_POWER_PROFILE_POWERSAVING = 0x2,
+ PP_SMC_POWER_PROFILE_VIDEO = 0x3,
+ PP_SMC_POWER_PROFILE_VR = 0x4,
+ PP_SMC_POWER_PROFILE_COMPUTE = 0x5,
+ PP_SMC_POWER_PROFILE_CUSTOM = 0x6,
};
enum {
@@ -280,6 +284,11 @@ struct amd_pm_funcs {
int (*set_hard_min_dcefclk_by_freq)(void *handle, uint32_t clock);
int (*set_hard_min_fclk_by_freq)(void *handle, uint32_t clock);
int (*set_min_deep_sleep_dcefclk)(void *handle, uint32_t clock);
+ int (*get_asic_baco_capability)(void *handle, bool *cap);
+ int (*get_asic_baco_state)(void *handle, int *state);
+ int (*set_asic_baco_state)(void *handle, int state);
+ int (*get_ppfeature_status)(void *handle, char *buf);
+ int (*set_ppfeature_status)(void *handle, uint64_t ppfeature_masks);
};
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
index 9bc27f468d5b..3f73f7cd18b9 100644
--- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -1404,6 +1404,97 @@ static int pp_set_active_display_count(void *handle, uint32_t count)
return ret;
}
+static int pp_get_asic_baco_capability(void *handle, bool *cap)
+{
+ struct pp_hwmgr *hwmgr = handle;
+
+ if (!hwmgr)
+ return -EINVAL;
+
+ if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_capability)
+ return 0;
+
+ mutex_lock(&hwmgr->smu_lock);
+ hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr, cap);
+ mutex_unlock(&hwmgr->smu_lock);
+
+ return 0;
+}
+
+static int pp_get_asic_baco_state(void *handle, int *state)
+{
+ struct pp_hwmgr *hwmgr = handle;
+
+ if (!hwmgr)
+ return -EINVAL;
+
+ if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_state)
+ return 0;
+
+ mutex_lock(&hwmgr->smu_lock);
+ hwmgr->hwmgr_func->get_asic_baco_state(hwmgr, (enum BACO_STATE *)state);
+ mutex_unlock(&hwmgr->smu_lock);
+
+ return 0;
+}
+
+static int pp_set_asic_baco_state(void *handle, int state)
+{
+ struct pp_hwmgr *hwmgr = handle;
+
+ if (!hwmgr)
+ return -EINVAL;
+
+ if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_asic_baco_state)
+ return 0;
+
+ mutex_lock(&hwmgr->smu_lock);
+ hwmgr->hwmgr_func->set_asic_baco_state(hwmgr, (enum BACO_STATE)state);
+ mutex_unlock(&hwmgr->smu_lock);
+
+ return 0;
+}
+
+static int pp_get_ppfeature_status(void *handle, char *buf)
+{
+ struct pp_hwmgr *hwmgr = handle;
+ int ret = 0;
+
+ if (!hwmgr || !hwmgr->pm_en || !buf)
+ return -EINVAL;
+
+ if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) {
+ pr_info_ratelimited("%s was not implemented.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&hwmgr->smu_lock);
+ ret = hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf);
+ mutex_unlock(&hwmgr->smu_lock);
+
+ return ret;
+}
+
+static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks)
+{
+ struct pp_hwmgr *hwmgr = handle;
+ int ret = 0;
+
+ if (!hwmgr || !hwmgr->pm_en)
+ return -EINVAL;
+
+ if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) {
+ pr_info_ratelimited("%s was not implemented.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&hwmgr->smu_lock);
+ ret = hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks);
+ mutex_unlock(&hwmgr->smu_lock);
+
+ return ret;
+}
+
static const struct amd_pm_funcs pp_dpm_funcs = {
.load_firmware = pp_dpm_load_fw,
.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
@@ -1454,4 +1545,9 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
.set_min_deep_sleep_dcefclk = pp_set_min_deep_sleep_dcefclk,
.set_hard_min_dcefclk_by_freq = pp_set_hard_min_dcefclk_by_freq,
.set_hard_min_fclk_by_freq = pp_set_hard_min_fclk_by_freq,
+ .get_asic_baco_capability = pp_get_asic_baco_capability,
+ .get_asic_baco_state = pp_get_asic_baco_state,
+ .set_asic_baco_state = pp_set_asic_baco_state,
+ .get_ppfeature_status = pp_get_ppfeature_status,
+ .set_ppfeature_status = pp_set_ppfeature_status,
};
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
index ade8973b6f4d..0b3c6d1d52e4 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
@@ -35,7 +35,7 @@ HARDWARE_MGR = hwmgr.o processpptables.o \
vega12_thermal.o \
pp_overdriver.o smu_helper.o \
vega20_processpptables.o vega20_hwmgr.o vega20_powertune.o \
- vega20_thermal.o
+ vega20_thermal.o common_baco.o vega10_baco.o vega20_baco.o
AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c
new file mode 100644
index 000000000000..9c57c1f67749
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "common_baco.h"
+
+
+static bool baco_wait_register(struct pp_hwmgr *hwmgr, u32 reg, u32 mask, u32 value)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ u32 timeout = 5000, data;
+
+ do {
+ msleep(1);
+ data = RREG32(reg);
+ timeout--;
+ } while (value != (data & mask) && (timeout != 0));
+
+ if (timeout == 0)
+ return false;
+
+ return true;
+}
+
+static bool baco_cmd_handler(struct pp_hwmgr *hwmgr, u32 command, u32 reg, u32 mask,
+ u32 shift, u32 value, u32 timeout)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ u32 data;
+ bool ret = true;
+
+ switch (command) {
+ case CMD_WRITE:
+ WREG32(reg, value << shift);
+ break;
+ case CMD_READMODIFYWRITE:
+ data = RREG32(reg);
+ data = (data & (~mask)) | (value << shift);
+ WREG32(reg, data);
+ break;
+ case CMD_WAITFOR:
+ ret = baco_wait_register(hwmgr, reg, mask, value);
+ break;
+ case CMD_DELAY_MS:
+ if (timeout)
+ /* Delay in milli Seconds */
+ msleep(timeout);
+ break;
+ case CMD_DELAY_US:
+ if (timeout)
+ /* Delay in micro Seconds */
+ udelay(timeout);
+ break;
+
+ default:
+ dev_warn(adev->dev, "Invalid BACO command.\n");
+ ret = false;
+ }
+
+ return ret;
+}
+
+bool soc15_baco_program_registers(struct pp_hwmgr *hwmgr,
+ const struct soc15_baco_cmd_entry *entry,
+ const u32 array_size)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ u32 i, reg = 0;
+
+ for (i = 0; i < array_size; i++) {
+ if ((entry[i].cmd == CMD_WRITE) ||
+ (entry[i].cmd == CMD_READMODIFYWRITE) ||
+ (entry[i].cmd == CMD_WAITFOR))
+ reg = adev->reg_offset[entry[i].hwip][entry[i].inst][entry[i].seg]
+ + entry[i].reg_offset;
+ if (!baco_cmd_handler(hwmgr, entry[i].cmd, reg, entry[i].mask,
+ entry[i].shift, entry[i].val, entry[i].timeout))
+ return false;
+ }
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h
index 26355c088746..95296c916f4e 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
+ * Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -19,25 +19,32 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: AMD
- *
*/
+#ifndef __COMMON_BOCO_H__
+#define __COMMON_BOCO_H__
+#include "hwmgr.h"
-#ifndef __DAL_I2C_SW_ENGINE_DCE80_H__
-#define __DAL_I2C_SW_ENGINE_DCE80_H__
-struct i2c_sw_engine_dce80 {
- struct i2c_sw_engine base;
- uint32_t engine_id;
+enum baco_cmd_type {
+ CMD_WRITE = 0,
+ CMD_READMODIFYWRITE,
+ CMD_WAITFOR,
+ CMD_DELAY_MS,
+ CMD_DELAY_US,
};
-struct i2c_sw_engine_dce80_create_arg {
- uint32_t engine_id;
- uint32_t default_speed;
- struct dc_context *ctx;
+struct soc15_baco_cmd_entry {
+ enum baco_cmd_type cmd;
+ uint32_t hwip;
+ uint32_t inst;
+ uint32_t seg;
+ uint32_t reg_offset;
+ uint32_t mask;
+ uint32_t shift;
+ uint32_t timeout;
+ uint32_t val;
};
-
-struct i2c_engine *dal_i2c_sw_engine_dce80_create(
- const struct i2c_sw_engine_dce80_create_arg *arg);
-
+extern bool soc15_baco_program_registers(struct pp_hwmgr *hwmgr,
+ const struct soc15_baco_cmd_entry *entry,
+ const u32 array_size);
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
index 1f92a9f4c9e3..c1c51c115e57 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
@@ -154,15 +154,6 @@ int phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
return 0;
}
-int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
-{
- PHM_FUNC_CHECK(hwmgr);
-
- if (NULL != hwmgr->hwmgr_func->enable_clock_power_gating)
- return hwmgr->hwmgr_func->enable_clock_power_gating(hwmgr);
-
- return 0;
-}
int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)
{
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
index 0173d0480024..6cd6497c6fc2 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
@@ -64,17 +64,19 @@ static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr);
static void hwmgr_init_workload_prority(struct pp_hwmgr *hwmgr)
{
- hwmgr->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 2;
- hwmgr->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 0;
- hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 1;
- hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VR] = 3;
- hwmgr->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 4;
-
- hwmgr->workload_setting[0] = PP_SMC_POWER_PROFILE_POWERSAVING;
- hwmgr->workload_setting[1] = PP_SMC_POWER_PROFILE_VIDEO;
- hwmgr->workload_setting[2] = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
- hwmgr->workload_setting[3] = PP_SMC_POWER_PROFILE_VR;
- hwmgr->workload_setting[4] = PP_SMC_POWER_PROFILE_COMPUTE;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
+ hwmgr->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
+
+ hwmgr->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ hwmgr->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
+ hwmgr->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING;
+ hwmgr->workload_setting[3] = PP_SMC_POWER_PROFILE_VIDEO;
+ hwmgr->workload_setting[4] = PP_SMC_POWER_PROFILE_VR;
+ hwmgr->workload_setting[5] = PP_SMC_POWER_PROFILE_COMPUTE;
}
int hwmgr_early_init(struct pp_hwmgr *hwmgr)
@@ -271,7 +273,7 @@ int hwmgr_hw_fini(struct pp_hwmgr *hwmgr)
phm_stop_thermal_controller(hwmgr);
psm_set_boot_states(hwmgr);
- psm_adjust_power_state_dynamic(hwmgr, false, NULL);
+ psm_adjust_power_state_dynamic(hwmgr, true, NULL);
phm_disable_dynamic_state_management(hwmgr);
phm_disable_clock_power_gatings(hwmgr);
@@ -293,7 +295,7 @@ int hwmgr_suspend(struct pp_hwmgr *hwmgr)
ret = psm_set_boot_states(hwmgr);
if (ret)
return ret;
- ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL);
+ ret = psm_adjust_power_state_dynamic(hwmgr, true, NULL);
if (ret)
return ret;
ret = phm_power_down_asic(hwmgr);
@@ -323,7 +325,7 @@ int hwmgr_resume(struct pp_hwmgr *hwmgr)
if (ret)
return ret;
- ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL);
+ ret = psm_adjust_power_state_dynamic(hwmgr, true, NULL);
return ret;
}
@@ -377,12 +379,12 @@ int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id,
ret = psm_set_user_performance_state(hwmgr, requested_ui_label, &requested_ps);
if (ret)
return ret;
- ret = psm_adjust_power_state_dynamic(hwmgr, false, requested_ps);
+ ret = psm_adjust_power_state_dynamic(hwmgr, true, requested_ps);
break;
}
case AMD_PP_TASK_COMPLETE_INIT:
case AMD_PP_TASK_READJUST_POWER_STATE:
- ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL);
+ ret = psm_adjust_power_state_dynamic(hwmgr, true, NULL);
break;
default:
break;
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c
index 56437866d120..ce177d7f04cb 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c
@@ -256,16 +256,14 @@ static void power_state_management(struct pp_hwmgr *hwmgr,
}
}
-int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip,
+int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_settings,
struct pp_power_state *new_ps)
{
uint32_t index;
long workload;
- if (skip)
- return 0;
-
- phm_display_configuration_changed(hwmgr);
+ if (!skip_display_settings)
+ phm_display_configuration_changed(hwmgr);
if (hwmgr->ps)
power_state_management(hwmgr, new_ps);
@@ -276,9 +274,11 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip,
*/
phm_apply_clock_adjust_rules(hwmgr);
- phm_notify_smc_display_config_after_ps_adjustment(hwmgr);
+ if (!skip_display_settings)
+ phm_notify_smc_display_config_after_ps_adjustment(hwmgr);
- if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level))
+ if ((hwmgr->request_dpm_level != hwmgr->dpm_level) &&
+ !phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level))
hwmgr->dpm_level = hwmgr->request_dpm_level;
if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h
index fa1b6825036a..b62d55f1f289 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h
@@ -34,7 +34,7 @@ int psm_set_user_performance_state(struct pp_hwmgr *hwmgr,
enum PP_StateUILabel label_id,
struct pp_power_state **state);
int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr,
- bool skip,
+ bool skip_display_settings,
struct pp_power_state *new_ps);
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
index f95c5f50eb0f..5273de3c5b98 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
@@ -1033,6 +1033,7 @@ static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
break;
case amd_pp_dpp_clock:
pclk_vol_table = pinfo->vdd_dep_on_dppclk;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
index d91390459326..c8f5c00dd1e7 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
@@ -77,8 +77,9 @@
#define PCIE_BUS_CLK 10000
#define TCLK (PCIE_BUS_CLK / 10)
-static const struct profile_mode_setting smu7_profiling[6] =
- {{1, 0, 100, 30, 1, 0, 100, 10},
+static const struct profile_mode_setting smu7_profiling[7] =
+ {{0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 0, 100, 30, 1, 0, 100, 10},
{1, 10, 0, 30, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 10, 16, 31},
{1, 0, 11, 50, 1, 0, 100, 10},
@@ -4889,7 +4890,8 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
uint32_t i, size = 0;
uint32_t len;
- static const char *profile_name[6] = {"3D_FULL_SCREEN",
+ static const char *profile_name[7] = {"BOOTUP_DEFAULT",
+ "3D_FULL_SCREEN",
"POWER_SAVING",
"VIDEO",
"VR",
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c
new file mode 100644
index 000000000000..f94dab27f486
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c
@@ -0,0 +1,136 @@
+#include "amdgpu.h"
+#include "soc15.h"
+#include "soc15_hw_ip.h"
+#include "vega10_ip_offset.h"
+#include "soc15_common.h"
+#include "vega10_inc.h"
+#include "vega10_ppsmc.h"
+#include "vega10_baco.h"
+
+
+
+static const struct soc15_baco_cmd_entry pre_baco_tbl[] =
+{
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIF_DOORBELL_CNTL), BIF_DOORBELL_CNTL__DOORBELL_MONITOR_EN_MASK, BIF_DOORBELL_CNTL__DOORBELL_MONITOR_EN__SHIFT, 0, 1},
+ {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIF_FB_EN), 0, 0, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_DSTATE_BYPASS_MASK, BACO_CNTL__BACO_DSTATE_BYPASS__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_RST_INTR_MASK_MASK, BACO_CNTL__BACO_RST_INTR_MASK__SHIFT, 0, 1}
+};
+
+static const struct soc15_baco_cmd_entry enter_baco_tbl[] =
+{
+ {CMD_WAITFOR, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__SOC_DOMAIN_IDLE_MASK, THM_BACO_CNTL__SOC_DOMAIN_IDLE__SHIFT, 0xffffffff, 0x80000000},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_BIF_LCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_LCLK_SWITCH__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_DUMMY_EN_MASK, BACO_CNTL__BACO_DUMMY_EN__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SOC_VDCI_RESET_MASK, THM_BACO_CNTL__BACO_SOC_VDCI_RESET__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SMNCLK_MUX_MASK, THM_BACO_CNTL__BACO_SMNCLK_MUX__SHIFT,0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_ISO_EN_MASK, THM_BACO_CNTL__BACO_ISO_EN__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_AEB_ISO_EN_MASK, THM_BACO_CNTL__BACO_AEB_ISO_EN__SHIFT,0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_ANA_ISO_EN_MASK, THM_BACO_CNTL__BACO_ANA_ISO_EN__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SOC_REFCLK_OFF_MASK, THM_BACO_CNTL__BACO_SOC_REFCLK_OFF__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 1},
+ {CMD_DELAY_MS, 0, 0, 0, 0, 0, 0, 5, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_RESET_EN_MASK, THM_BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_PWROKRAW_CNTL_MASK, THM_BACO_CNTL__BACO_PWROKRAW_CNTL__SHIFT, 0, 0},
+ {CMD_WAITFOR, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_MODE_MASK, BACO_CNTL__BACO_MODE__SHIFT, 0xffffffff, 0x100}
+};
+
+static const struct soc15_baco_cmd_entry exit_baco_tbl[] =
+{
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0},
+ {CMD_DELAY_MS, 0, 0, 0, 0, 0, 0, 10,0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SOC_REFCLK_OFF_MASK, THM_BACO_CNTL__BACO_SOC_REFCLK_OFF__SHIFT, 0,0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_ANA_ISO_EN_MASK, THM_BACO_CNTL__BACO_ANA_ISO_EN__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_AEB_ISO_EN_MASK, THM_BACO_CNTL__BACO_AEB_ISO_EN__SHIFT,0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_ISO_EN_MASK, THM_BACO_CNTL__BACO_ISO_EN__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_PWROKRAW_CNTL_MASK, THM_BACO_CNTL__BACO_PWROKRAW_CNTL__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SMNCLK_MUX_MASK, THM_BACO_CNTL__BACO_SMNCLK_MUX__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SOC_VDCI_RESET_MASK, THM_BACO_CNTL__BACO_SOC_VDCI_RESET__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_EXIT_MASK, THM_BACO_CNTL__BACO_EXIT__SHIFT, 0, 1},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_RESET_EN_MASK, THM_BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0},
+ {CMD_WAITFOR, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_EXIT_MASK, 0, 0xffffffff, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(THM, 0, mmTHM_BACO_CNTL), THM_BACO_CNTL__BACO_SB_AXI_FENCE_MASK, THM_BACO_CNTL__BACO_SB_AXI_FENCE__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_DUMMY_EN_MASK, BACO_CNTL__BACO_DUMMY_EN__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_BIF_LCLK_SWITCH_MASK ,BACO_CNTL__BACO_BIF_LCLK_SWITCH__SHIFT, 0, 0},
+ {CMD_READMODIFYWRITE, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_EN_MASK , BACO_CNTL__BACO_EN__SHIFT, 0,0},
+ {CMD_WAITFOR, SOC15_REG_ENTRY(NBIF, 0, mmBACO_CNTL), BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0}
+ };
+
+static const struct soc15_baco_cmd_entry clean_baco_tbl[] =
+{
+ {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_6), 0, 0, 0, 0},
+ {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_7), 0, 0, 0, 0},
+};
+
+int vega10_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ uint32_t reg, data;
+
+ *cap = false;
+ if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO))
+ return 0;
+
+ WREG32(0x12074, 0xFFF0003B);
+ data = RREG32(0x12075);
+
+ if (data == 0x1) {
+ reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0);
+
+ if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK)
+ *cap = true;
+ }
+
+ return 0;
+}
+
+int vega10_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ uint32_t reg;
+
+ reg = RREG32_SOC15(NBIF, 0, mmBACO_CNTL);
+
+ if (reg & BACO_CNTL__BACO_MODE_MASK)
+ /* gfx has already entered BACO state */
+ *state = BACO_STATE_IN;
+ else
+ *state = BACO_STATE_OUT;
+ return 0;
+}
+
+int vega10_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state)
+{
+ enum BACO_STATE cur_state;
+
+ vega10_baco_get_state(hwmgr, &cur_state);
+
+ if (cur_state == state)
+ /* aisc already in the target state */
+ return 0;
+
+ if (state == BACO_STATE_IN) {
+ if (soc15_baco_program_registers(hwmgr, pre_baco_tbl,
+ ARRAY_SIZE(pre_baco_tbl))) {
+ if (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnterBaco))
+ return -1;
+
+ if (soc15_baco_program_registers(hwmgr, enter_baco_tbl,
+ ARRAY_SIZE(enter_baco_tbl)))
+ return 0;
+ }
+ } else if (state == BACO_STATE_OUT) {
+ /* HW requires at least 20ms between regulator off and on */
+ msleep(20);
+ /* Execute Hardware BACO exit sequence */
+ if (soc15_baco_program_registers(hwmgr, exit_baco_tbl,
+ ARRAY_SIZE(exit_baco_tbl))) {
+ if (soc15_baco_program_registers(hwmgr, clean_baco_tbl,
+ ARRAY_SIZE(clean_baco_tbl)))
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.h
index 21908629e973..a93b1e6d1c66 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
+ * Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -19,20 +19,14 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: AMD
- *
*/
+#ifndef __VEGA10_BOCO_H__
+#define __VEGA10_BOCO_H__
+#include "hwmgr.h"
+#include "common_baco.h"
-#ifndef __DAL_I2C_AUX_DCE80_H__
-#define __DAL_I2C_AUX_DCE80_H__
-
-struct i2caux_dce80 {
- struct i2caux base;
- /* indicate the I2C HW circular buffer is in use */
- bool i2c_hw_buffer_in_use;
-};
-
-struct i2caux *dal_i2caux_dce80_create(
- struct dc_context *ctx);
+extern int vega10_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap);
+extern int vega10_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);
+extern int vega10_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state);
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
index 79c86247d0ac..5479125ff4f6 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
@@ -48,6 +48,7 @@
#include "ppinterrupt.h"
#include "pp_overdriver.h"
#include "pp_thermal.h"
+#include "vega10_baco.h"
#include "smuio/smuio_9_0_offset.h"
#include "smuio/smuio_9_0_sh_mask.h"
@@ -71,6 +72,21 @@ static const uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2};
#define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel_MASK 0x00000700L
#define DF_CS_AON0_DramBaseAddress0__DramBaseAddr_MASK 0xFFFFF000L
+typedef enum {
+ CLK_SMNCLK = 0,
+ CLK_SOCCLK,
+ CLK_MP0CLK,
+ CLK_MP1CLK,
+ CLK_LCLK,
+ CLK_DCEFCLK,
+ CLK_VCLK,
+ CLK_DCLK,
+ CLK_ECLK,
+ CLK_UCLK,
+ CLK_GFXCLK,
+ CLK_COUNT,
+} CLOCK_ID_e;
+
static const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic);
struct vega10_power_state *cast_phw_vega10_power_state(
@@ -804,9 +820,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
hwmgr->backend = data;
- hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO];
- hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
- hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
+ hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
+ hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
vega10_set_default_registry_data(hwmgr);
data->disable_dpm_mask = 0xff;
@@ -3485,6 +3501,17 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr)
}
}
+ if (!data->registry_data.socclk_dpm_key_disabled) {
+ if (data->smc_state_table.soc_boot_level !=
+ data->dpm_table.soc_table.dpm_state.soft_min_level) {
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetSoftMinSocclkByIndex,
+ data->smc_state_table.soc_boot_level);
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->smc_state_table.soc_boot_level;
+ }
+ }
+
return 0;
}
@@ -3516,6 +3543,17 @@ static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr)
}
}
+ if (!data->registry_data.socclk_dpm_key_disabled) {
+ if (data->smc_state_table.soc_max_level !=
+ data->dpm_table.soc_table.dpm_state.soft_max_level) {
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetSoftMaxSocclkByIndex,
+ data->smc_state_table.soc_max_level);
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->smc_state_table.soc_max_level;
+ }
+ }
+
return 0;
}
@@ -3541,6 +3579,10 @@ static int vega10_generate_dpm_level_enable_mask(
vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
data->smc_state_table.mem_max_level =
vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
+ data->smc_state_table.soc_boot_level =
+ vega10_find_lowest_dpm_level(&(data->dpm_table.soc_table));
+ data->smc_state_table.soc_max_level =
+ vega10_find_highest_dpm_level(&(data->dpm_table.soc_table));
PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
"Attempt to upload DPM Bootup Levels Failed!",
@@ -3555,6 +3597,9 @@ static int vega10_generate_dpm_level_enable_mask(
for(i = data->smc_state_table.mem_boot_level; i < data->smc_state_table.mem_max_level; i++)
data->dpm_table.mem_table.dpm_levels[i].enabled = true;
+ for (i = data->smc_state_table.soc_boot_level; i < data->smc_state_table.soc_max_level; i++)
+ data->dpm_table.soc_table.dpm_levels[i].enabled = true;
+
return 0;
}
@@ -4028,6 +4073,24 @@ static int vega10_force_clock_level(struct pp_hwmgr *hwmgr,
break;
+ case PP_SOCCLK:
+ data->smc_state_table.soc_boot_level = mask ? (ffs(mask) - 1) : 0;
+ data->smc_state_table.soc_max_level = mask ? (fls(mask) - 1) : 0;
+
+ PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
+ "Failed to upload boot level to lowest!",
+ return -EINVAL);
+
+ PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
+ "Failed to upload dpm max level to highest!",
+ return -EINVAL);
+
+ break;
+
+ case PP_DCEFCLK:
+ pr_info("Setting DCEFCLK min/max dpm level is not supported!\n");
+ break;
+
case PP_PCIE:
default:
break;
@@ -4267,12 +4330,113 @@ static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
return result;
}
+static int vega10_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+{
+ static const char *ppfeature_name[] = {
+ "DPM_PREFETCHER",
+ "GFXCLK_DPM",
+ "UCLK_DPM",
+ "SOCCLK_DPM",
+ "UVD_DPM",
+ "VCE_DPM",
+ "ULV",
+ "MP0CLK_DPM",
+ "LINK_DPM",
+ "DCEFCLK_DPM",
+ "AVFS",
+ "GFXCLK_DS",
+ "SOCCLK_DS",
+ "LCLK_DS",
+ "PPT",
+ "TDC",
+ "THERMAL",
+ "GFX_PER_CU_CG",
+ "RM",
+ "DCEFCLK_DS",
+ "ACDC",
+ "VR0HOT",
+ "VR1HOT",
+ "FW_CTF",
+ "LED_DISPLAY",
+ "FAN_CONTROL",
+ "FAST_PPT",
+ "DIDT",
+ "ACG",
+ "PCC_LIMIT"};
+ static const char *output_title[] = {
+ "FEATURES",
+ "BITMASK",
+ "ENABLEMENT"};
+ uint64_t features_enabled;
+ int i;
+ int ret = 0;
+ int size = 0;
+
+ ret = vega10_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+ return ret);
+
+ size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled);
+ size += sprintf(buf + size, "%-19s %-22s %s\n",
+ output_title[0],
+ output_title[1],
+ output_title[2]);
+ for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+ size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
+ ppfeature_name[i],
+ 1ULL << i,
+ (features_enabled & (1ULL << i)) ? "Y" : "N");
+ }
+
+ return size;
+}
+
+static int vega10_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
+{
+ uint64_t features_enabled;
+ uint64_t features_to_enable;
+ uint64_t features_to_disable;
+ int ret = 0;
+
+ if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
+ return -EINVAL;
+
+ ret = vega10_get_enabled_smc_features(hwmgr, &features_enabled);
+ if (ret)
+ return ret;
+
+ features_to_disable =
+ (features_enabled ^ new_ppfeature_masks) & features_enabled;
+ features_to_enable =
+ (features_enabled ^ new_ppfeature_masks) ^ features_to_disable;
+
+ pr_debug("features_to_disable 0x%llx\n", features_to_disable);
+ pr_debug("features_to_enable 0x%llx\n", features_to_enable);
+
+ if (features_to_disable) {
+ ret = vega10_enable_smc_features(hwmgr, false, features_to_disable);
+ if (ret)
+ return ret;
+ }
+
+ if (features_to_enable) {
+ ret = vega10_enable_smc_features(hwmgr, true, features_to_enable);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, char *buf)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
+ struct vega10_single_dpm_table *soc_table = &(data->dpm_table.soc_table);
+ struct vega10_single_dpm_table *dcef_table = &(data->dpm_table.dcef_table);
struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table);
struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL;
@@ -4303,6 +4467,32 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
i, mclk_table->dpm_levels[i].value / 100,
(i == now) ? "*" : "");
break;
+ case PP_SOCCLK:
+ if (data->registry_data.socclk_dpm_key_disabled)
+ break;
+
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex);
+ now = smum_get_argument(hwmgr);
+
+ for (i = 0; i < soc_table->count; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, soc_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+ case PP_DCEFCLK:
+ if (data->registry_data.dcefclk_dpm_key_disabled)
+ break;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK);
+ now = smum_get_argument(hwmgr);
+
+ for (i = 0; i < dcef_table->count; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, dcef_table->dpm_levels[i].value / 100,
+ (dcef_table->dpm_levels[i].value / 100 == now) ?
+ "*" : "");
+ break;
case PP_PCIE:
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentLinkIndex);
now = smum_get_argument(hwmgr);
@@ -4668,13 +4858,15 @@ static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
{
struct vega10_hwmgr *data = hwmgr->backend;
uint32_t i, size = 0;
- static const uint8_t profile_mode_setting[5][4] = {{70, 60, 1, 3,},
+ static const uint8_t profile_mode_setting[6][4] = {{70, 60, 0, 0,},
+ {70, 60, 1, 3,},
{90, 60, 0, 0,},
{70, 60, 0, 0,},
{70, 90, 0, 0,},
{30, 60, 0, 6,},
};
- static const char *profile_name[6] = {"3D_FULL_SCREEN",
+ static const char *profile_name[7] = {"BOOTUP_DEFAULT",
+ "3D_FULL_SCREEN",
"POWER_SAVING",
"VIDEO",
"VR",
@@ -4978,6 +5170,12 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
.set_power_limit = vega10_set_power_limit,
.odn_edit_dpm_table = vega10_odn_edit_dpm_table,
.get_performance_level = vega10_get_performance_level,
+ .get_asic_baco_capability = vega10_baco_get_capability,
+ .get_asic_baco_state = vega10_baco_get_state,
+ .set_asic_baco_state = vega10_baco_set_state,
+ .enable_mgpu_fan_boost = vega10_enable_mgpu_fan_boost,
+ .get_ppfeature_status = vega10_get_ppfeature_status,
+ .set_ppfeature_status = vega10_set_ppfeature_status,
};
int vega10_hwmgr_init(struct pp_hwmgr *hwmgr)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h
index 89870556de1b..f752b4ad0c8a 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h
@@ -199,6 +199,7 @@ struct vega10_smc_state_table {
uint32_t vce_boot_level;
uint32_t gfx_max_level;
uint32_t mem_max_level;
+ uint32_t soc_max_level;
uint8_t vr_hot_gpio;
uint8_t ac_dc_gpio;
uint8_t therm_out_gpio;
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h
index b3e63003a789..c934e9612c1b 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h
@@ -282,6 +282,30 @@ typedef struct _ATOM_Vega10_Fan_Table_V2 {
UCHAR ucFanMaxRPM;
} ATOM_Vega10_Fan_Table_V2;
+typedef struct _ATOM_Vega10_Fan_Table_V3 {
+ UCHAR ucRevId;
+ USHORT usFanOutputSensitivity;
+ USHORT usFanAcousticLimitRpm;
+ USHORT usThrottlingRPM;
+ USHORT usTargetTemperature;
+ USHORT usMinimumPWMLimit;
+ USHORT usTargetGfxClk;
+ USHORT usFanGainEdge;
+ USHORT usFanGainHotspot;
+ USHORT usFanGainLiquid;
+ USHORT usFanGainVrVddc;
+ USHORT usFanGainVrMvdd;
+ USHORT usFanGainPlx;
+ USHORT usFanGainHbm;
+ UCHAR ucEnableZeroRPM;
+ USHORT usFanStopTemperature;
+ USHORT usFanStartTemperature;
+ UCHAR ucFanParameters;
+ UCHAR ucFanMinRPM;
+ UCHAR ucFanMaxRPM;
+ USHORT usMGpuThrottlingRPM;
+} ATOM_Vega10_Fan_Table_V3;
+
typedef struct _ATOM_Vega10_Thermal_Controller {
UCHAR ucRevId;
UCHAR ucType; /* one of ATOM_VEGA10_PP_THERMALCONTROLLER_*/
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c
index b8747a5c9204..b6767d74dc85 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c
@@ -32,6 +32,7 @@
#include "vega10_pptable.h"
#define NUM_DSPCLK_LEVELS 8
+#define VEGA10_ENGINECLOCK_HARDMAX 198000
static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
enum phm_platform_caps cap)
@@ -122,6 +123,7 @@ static int init_thermal_controller(
const Vega10_PPTable_Generic_SubTable_Header *header;
const ATOM_Vega10_Fan_Table *fan_table_v1;
const ATOM_Vega10_Fan_Table_V2 *fan_table_v2;
+ const ATOM_Vega10_Fan_Table_V3 *fan_table_v3;
thermal_controller = (ATOM_Vega10_Thermal_Controller *)
(((unsigned long)powerplay_table) +
@@ -206,7 +208,7 @@ static int init_thermal_controller(
le16_to_cpu(fan_table_v1->usFanStopTemperature);
hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature =
le16_to_cpu(fan_table_v1->usFanStartTemperature);
- } else if (header->ucRevId > 10) {
+ } else if (header->ucRevId == 0xb) {
fan_table_v2 = (ATOM_Vega10_Fan_Table_V2 *)header;
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
@@ -250,7 +252,54 @@ static int init_thermal_controller(
le16_to_cpu(fan_table_v2->usFanStopTemperature);
hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature =
le16_to_cpu(fan_table_v2->usFanStartTemperature);
+ } else if (header->ucRevId > 0xb) {
+ fan_table_v3 = (ATOM_Vega10_Fan_Table_V3 *)header;
+
+ hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
+ fan_table_v3->ucFanParameters & ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+ hwmgr->thermal_controller.fanInfo.ulMinRPM = fan_table_v3->ucFanMinRPM * 100UL;
+ hwmgr->thermal_controller.fanInfo.ulMaxRPM = fan_table_v3->ucFanMaxRPM * 100UL;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
+ le16_to_cpu(fan_table_v3->usFanOutputSensitivity);
+ hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
+ fan_table_v3->ucFanMaxRPM * 100UL;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit =
+ le16_to_cpu(fan_table_v3->usThrottlingRPM);
+ hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit =
+ le16_to_cpu(fan_table_v3->usFanAcousticLimitRpm);
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMax =
+ le16_to_cpu(fan_table_v3->usTargetTemperature);
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin =
+ le16_to_cpu(fan_table_v3->usMinimumPWMLimit);
+ hwmgr->thermal_controller.advanceFanControlParameters.ulTargetGfxClk =
+ le16_to_cpu(fan_table_v3->usTargetGfxClk);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge =
+ le16_to_cpu(fan_table_v3->usFanGainEdge);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot =
+ le16_to_cpu(fan_table_v3->usFanGainHotspot);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid =
+ le16_to_cpu(fan_table_v3->usFanGainLiquid);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc =
+ le16_to_cpu(fan_table_v3->usFanGainVrVddc);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd =
+ le16_to_cpu(fan_table_v3->usFanGainVrMvdd);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx =
+ le16_to_cpu(fan_table_v3->usFanGainPlx);
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm =
+ le16_to_cpu(fan_table_v3->usFanGainHbm);
+
+ hwmgr->thermal_controller.advanceFanControlParameters.ucEnableZeroRPM =
+ fan_table_v3->ucEnableZeroRPM;
+ hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStopTemperature =
+ le16_to_cpu(fan_table_v3->usFanStopTemperature);
+ hwmgr->thermal_controller.advanceFanControlParameters.usZeroRPMStartTemperature =
+ le16_to_cpu(fan_table_v3->usFanStartTemperature);
+ hwmgr->thermal_controller.advanceFanControlParameters.usMGpuThrottlingRPMLimit =
+ le16_to_cpu(fan_table_v3->usMGpuThrottlingRPM);
}
+
return 0;
}
@@ -258,7 +307,26 @@ static int init_over_drive_limits(
struct pp_hwmgr *hwmgr,
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
{
- hwmgr->platform_descriptor.overdriveLimit.engineClock =
+ const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table =
+ (const ATOM_Vega10_GFXCLK_Dependency_Table *)
+ (((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset));
+ bool is_acg_enabled = false;
+ ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2;
+
+ if (gfxclk_dep_table->ucRevId == 1) {
+ patom_record_v2 =
+ (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries;
+ is_acg_enabled =
+ (bool)patom_record_v2[gfxclk_dep_table->ucNumEntries-1].ucACGEnable;
+ }
+
+ if (powerplay_table->ulMaxODEngineClock > VEGA10_ENGINECLOCK_HARDMAX &&
+ !is_acg_enabled)
+ hwmgr->platform_descriptor.overdriveLimit.engineClock =
+ VEGA10_ENGINECLOCK_HARDMAX;
+ else
+ hwmgr->platform_descriptor.overdriveLimit.engineClock =
le32_to_cpu(powerplay_table->ulMaxODEngineClock);
hwmgr->platform_descriptor.overdriveLimit.memoryClock =
le32_to_cpu(powerplay_table->ulMaxODMemoryClock);
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
index 3f807d6c95ce..ba8763daa380 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
@@ -556,6 +556,43 @@ int vega10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
return ret;
}
+int vega10_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data = hwmgr->backend;
+ PPTable_t *table = &(data->smc_state_table.pp_table);
+ int ret;
+
+ if (!data->smu_features[GNLD_FAN_CONTROL].supported)
+ return 0;
+
+ if (!hwmgr->thermal_controller.advanceFanControlParameters.
+ usMGpuThrottlingRPMLimit)
+ return 0;
+
+ table->FanThrottlingRpm = hwmgr->thermal_controller.
+ advanceFanControlParameters.usMGpuThrottlingRPMLimit;
+
+ ret = smum_smc_table_manager(hwmgr,
+ (uint8_t *)(&(data->smc_state_table.pp_table)),
+ PPTABLE, false);
+ if (ret) {
+ pr_info("Failed to update fan control table in pptable!");
+ return ret;
+ }
+
+ ret = vega10_disable_fan_control_feature(hwmgr);
+ if (ret) {
+ pr_info("Attempt to disable SMC fan control feature failed!");
+ return ret;
+ }
+
+ ret = vega10_enable_fan_control_feature(hwmgr);
+ if (ret)
+ pr_info("Attempt to enable SMC fan control feature failed!");
+
+ return ret;
+}
+
/**
* Start the fan control on the SMC.
* @param hwmgr the address of the powerplay hardware manager.
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h
index 21e7c4dfa2ca..4a0ede7c1f07 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h
@@ -73,6 +73,7 @@ extern int vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr);
extern int vega10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr);
extern int vega10_start_thermal_controller(struct pp_hwmgr *hwmgr,
struct PP_TemperatureRange *range);
+extern int vega10_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr);
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c
index 54364444ecd1..6c8e78611c03 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c
@@ -753,6 +753,22 @@ static int vega12_init_smc_table(struct pp_hwmgr *hwmgr)
return 0;
}
+static int vega12_run_acg_btc(struct pp_hwmgr *hwmgr)
+{
+ uint32_t result;
+
+ PP_ASSERT_WITH_CODE(
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgBtc) == 0,
+ "[Run_ACG_BTC] Attempt to run ACG BTC failed!",
+ return -EINVAL);
+
+ result = smum_get_argument(hwmgr);
+ PP_ASSERT_WITH_CODE(result == 1,
+ "Failed to run ACG BTC!", return -EINVAL);
+
+ return 0;
+}
+
static int vega12_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
{
struct vega12_hwmgr *data =
@@ -931,6 +947,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"Failed to initialize SMC table!",
result = tmp_result);
+ tmp_result = vega12_run_acg_btc(hwmgr);
+ PP_ASSERT_WITH_CODE(!tmp_result,
+ "Failed to run ACG BTC!",
+ result = tmp_result);
+
result = vega12_enable_all_smu_features(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to enable all smu features!",
@@ -1072,6 +1093,16 @@ static int vega12_upload_dpm_min_level(struct pp_hwmgr *hwmgr)
return ret);
}
+ if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
+ min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level;
+
+ PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
+ hwmgr, PPSMC_MSG_SetHardMinByFreq,
+ (PPCLK_DCEFCLK << 16) | (min_freq & 0xffff))),
+ "Failed to set hard min dcefclk!",
+ return ret);
+ }
+
return ret;
}
@@ -1797,7 +1828,7 @@ static int vega12_force_clock_level(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, uint32_t mask)
{
struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
- uint32_t soft_min_level, soft_max_level;
+ uint32_t soft_min_level, soft_max_level, hard_min_level;
int ret = 0;
switch (type) {
@@ -1842,6 +1873,56 @@ static int vega12_force_clock_level(struct pp_hwmgr *hwmgr,
break;
+ case PP_SOCCLK:
+ soft_min_level = mask ? (ffs(mask) - 1) : 0;
+ soft_max_level = mask ? (fls(mask) - 1) : 0;
+
+ if (soft_max_level >= data->dpm_table.soc_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ soft_max_level,
+ data->dpm_table.soc_table.count - 1);
+ return -EINVAL;
+ }
+
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
+
+ ret = vega12_upload_dpm_min_level(hwmgr);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload boot level to lowest!",
+ return ret);
+
+ ret = vega12_upload_dpm_max_level(hwmgr);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload dpm max level to highest!",
+ return ret);
+
+ break;
+
+ case PP_DCEFCLK:
+ hard_min_level = mask ? (ffs(mask) - 1) : 0;
+
+ if (hard_min_level >= data->dpm_table.dcef_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ hard_min_level,
+ data->dpm_table.dcef_table.count - 1);
+ return -EINVAL;
+ }
+
+ data->dpm_table.dcef_table.dpm_state.hard_min_level =
+ data->dpm_table.dcef_table.dpm_levels[hard_min_level].value;
+
+ ret = vega12_upload_dpm_min_level(hwmgr);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload boot level to lowest!",
+ return ret);
+
+ //TODO: Setting DCEFCLK max dpm level is not supported
+
+ break;
+
case PP_PCIE:
break;
@@ -1852,6 +1933,104 @@ static int vega12_force_clock_level(struct pp_hwmgr *hwmgr,
return 0;
}
+static int vega12_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+{
+ static const char *ppfeature_name[] = {
+ "DPM_PREFETCHER",
+ "GFXCLK_DPM",
+ "UCLK_DPM",
+ "SOCCLK_DPM",
+ "UVD_DPM",
+ "VCE_DPM",
+ "ULV",
+ "MP0CLK_DPM",
+ "LINK_DPM",
+ "DCEFCLK_DPM",
+ "GFXCLK_DS",
+ "SOCCLK_DS",
+ "LCLK_DS",
+ "PPT",
+ "TDC",
+ "THERMAL",
+ "GFX_PER_CU_CG",
+ "RM",
+ "DCEFCLK_DS",
+ "ACDC",
+ "VR0HOT",
+ "VR1HOT",
+ "FW_CTF",
+ "LED_DISPLAY",
+ "FAN_CONTROL",
+ "DIDT",
+ "GFXOFF",
+ "CG",
+ "ACG"};
+ static const char *output_title[] = {
+ "FEATURES",
+ "BITMASK",
+ "ENABLEMENT"};
+ uint64_t features_enabled;
+ int i;
+ int ret = 0;
+ int size = 0;
+
+ ret = vega12_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+ return ret);
+
+ size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled);
+ size += sprintf(buf + size, "%-19s %-22s %s\n",
+ output_title[0],
+ output_title[1],
+ output_title[2]);
+ for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+ size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
+ ppfeature_name[i],
+ 1ULL << i,
+ (features_enabled & (1ULL << i)) ? "Y" : "N");
+ }
+
+ return size;
+}
+
+static int vega12_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
+{
+ uint64_t features_enabled;
+ uint64_t features_to_enable;
+ uint64_t features_to_disable;
+ int ret = 0;
+
+ if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
+ return -EINVAL;
+
+ ret = vega12_get_enabled_smc_features(hwmgr, &features_enabled);
+ if (ret)
+ return ret;
+
+ features_to_disable =
+ (features_enabled ^ new_ppfeature_masks) & features_enabled;
+ features_to_enable =
+ (features_enabled ^ new_ppfeature_masks) ^ features_to_disable;
+
+ pr_debug("features_to_disable 0x%llx\n", features_to_disable);
+ pr_debug("features_to_enable 0x%llx\n", features_to_enable);
+
+ if (features_to_disable) {
+ ret = vega12_enable_smc_features(hwmgr, false, features_to_disable);
+ if (ret)
+ return ret;
+ }
+
+ if (features_to_enable) {
+ ret = vega12_enable_smc_features(hwmgr, true, features_to_enable);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, char *buf)
{
@@ -1891,6 +2070,42 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
(clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : "");
break;
+ case PP_SOCCLK:
+ PP_ASSERT_WITH_CODE(
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_GetDpmClockFreq, (PPCLK_SOCCLK << 16)) == 0,
+ "Attempt to get Current SOCCLK Frequency Failed!",
+ return -EINVAL);
+ now = smum_get_argument(hwmgr);
+
+ PP_ASSERT_WITH_CODE(
+ vega12_get_socclocks(hwmgr, &clocks) == 0,
+ "Attempt to get soc clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ break;
+
+ case PP_DCEFCLK:
+ PP_ASSERT_WITH_CODE(
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_GetDpmClockFreq, (PPCLK_DCEFCLK << 16)) == 0,
+ "Attempt to get Current DCEFCLK Frequency Failed!",
+ return -EINVAL);
+ now = smum_get_argument(hwmgr);
+
+ PP_ASSERT_WITH_CODE(
+ vega12_get_dcefclocks(hwmgr, &clocks) == 0,
+ "Attempt to get dcef clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ break;
+
case PP_PCIE:
break;
@@ -2411,6 +2626,8 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = {
.start_thermal_controller = vega12_start_thermal_controller,
.powergate_gfx = vega12_gfx_off_control,
.get_performance_level = vega12_get_performance_level,
+ .get_ppfeature_status = vega12_get_ppfeature_status,
+ .set_ppfeature_status = vega12_set_ppfeature_status,
};
int vega12_hwmgr_init(struct pp_hwmgr *hwmgr)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c
new file mode 100644
index 000000000000..0d883b358df2
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c
@@ -0,0 +1,81 @@
+#include "amdgpu.h"
+#include "soc15.h"
+#include "soc15_hw_ip.h"
+#include "soc15_common.h"
+#include "vega20_inc.h"
+#include "vega20_ppsmc.h"
+#include "vega20_baco.h"
+
+
+
+static const struct soc15_baco_cmd_entry clean_baco_tbl[] =
+{
+ {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_6), 0, 0, 0, 0},
+ {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_7), 0, 0, 0, 0},
+};
+
+int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ uint32_t reg;
+
+ *cap = false;
+ if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO))
+ return 0;
+
+ if (((RREG32(0x17569) & 0x20000000) >> 29) == 0x1) {
+ reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0);
+
+ if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK)
+ *cap = true;
+ }
+
+ return 0;
+}
+
+int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ uint32_t reg;
+
+ reg = RREG32_SOC15(NBIF, 0, mmBACO_CNTL);
+
+ if (reg & BACO_CNTL__BACO_MODE_MASK)
+ /* gfx has already entered BACO state */
+ *state = BACO_STATE_IN;
+ else
+ *state = BACO_STATE_OUT;
+ return 0;
+}
+
+int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ enum BACO_STATE cur_state;
+ uint32_t data;
+
+ vega20_baco_get_state(hwmgr, &cur_state);
+
+ if (cur_state == state)
+ /* aisc already in the target state */
+ return 0;
+
+ if (state == BACO_STATE_IN) {
+ data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL);
+ data |= 0x80000000;
+ WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data);
+
+
+ if(smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnterBaco, 0))
+ return -1;
+
+ } else if (state == BACO_STATE_OUT) {
+ if (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ExitBaco))
+ return -1;
+ if (!soc15_baco_program_registers(hwmgr, clean_baco_tbl,
+ ARRAY_SIZE(clean_baco_tbl)))
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.h
index 2b508d3e0ef4..c51988a9ed77 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
+ * Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -19,14 +19,14 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: AMD
- *
*/
+#ifndef __VEGA20_BOCO_H__
+#define __VEGA20_BOCO_H__
+#include "hwmgr.h"
+#include "common_baco.h"
-#ifndef __DAL_I2C_AUX_DCE100_H__
-#define __DAL_I2C_AUX_DCE100_H__
-
-struct i2caux *dal_i2caux_dce100_create(
- struct dc_context *ctx);
+extern int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap);
+extern int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);
+extern int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state);
-#endif /* __DAL_I2C_AUX_DCE100_H__ */
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
index 26154f9b2178..0769b1ec562b 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
@@ -47,6 +47,7 @@
#include "pp_overdriver.h"
#include "pp_thermal.h"
#include "soc15_common.h"
+#include "vega20_baco.h"
#include "smuio/smuio_9_0_offset.h"
#include "smuio/smuio_9_0_sh_mask.h"
#include "nbio/nbio_7_4_sh_mask.h"
@@ -390,9 +391,9 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
hwmgr->backend = data;
- hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO];
- hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
- hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO;
+ hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
+ hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
vega20_set_default_registry_data(hwmgr);
@@ -770,6 +771,54 @@ static int vega20_init_smc_table(struct pp_hwmgr *hwmgr)
return 0;
}
+/*
+ * Override PCIe link speed and link width for DPM Level 1. PPTable entries
+ * reflect the ASIC capabilities and not the system capabilities. For e.g.
+ * Vega20 board in a PCI Gen3 system. In this case, when SMU's tries to switch
+ * to DPM1, it fails as system doesn't support Gen4.
+ */
+static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg;
+ int ret;
+
+ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
+ pcie_gen = 3;
+ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+ pcie_gen = 2;
+ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+ pcie_gen = 1;
+ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
+ pcie_gen = 0;
+
+ if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
+ pcie_width = 6;
+ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
+ pcie_width = 5;
+ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
+ pcie_width = 4;
+ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
+ pcie_width = 3;
+ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
+ pcie_width = 2;
+ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
+ pcie_width = 1;
+
+ /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
+ * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
+ * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32
+ */
+ smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width;
+ ret = smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_OverridePcieParameters, smu_pcie_arg);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[OverridePcieParameters] Attempt to override pcie params failed!",
+ return ret);
+
+ return 0;
+}
+
static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
{
struct vega20_hwmgr *data =
@@ -803,6 +852,11 @@ static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
return 0;
}
+static int vega20_run_btc(struct pp_hwmgr *hwmgr)
+{
+ return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunBtc);
+}
+
static int vega20_run_btc_afll(struct pp_hwmgr *hwmgr)
{
return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAfllBtc);
@@ -980,6 +1034,9 @@ static int vega20_od8_set_feature_capabilities(
pp_table->FanZeroRpmEnable)
od_settings->overdrive8_capabilities |= OD8_FAN_ZERO_RPM_CONTROL;
+ if (!od_settings->overdrive8_capabilities)
+ hwmgr->od_enabled = false;
+
return 0;
}
@@ -1561,6 +1618,11 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"[EnableDPMTasks] Failed to initialize SMC table!",
return result);
+ result = vega20_run_btc(hwmgr);
+ PP_ASSERT_WITH_CODE(!result,
+ "[EnableDPMTasks] Failed to run btc!",
+ return result);
+
result = vega20_run_btc_afll(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"[EnableDPMTasks] Failed to run btc afll!",
@@ -1571,6 +1633,11 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"[EnableDPMTasks] Failed to enable all smu features!",
return result);
+ result = vega20_override_pcie_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE(!result,
+ "[EnableDPMTasks] Failed to override pcie parameters!",
+ return result);
+
result = vega20_notify_smc_display_change(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"[EnableDPMTasks] Failed to notify smc display change!",
@@ -1689,13 +1756,6 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_
(PPCLK_UCLK << 16) | (min_freq & 0xffff))),
"Failed to set soft min memclk !",
return ret);
-
- min_freq = data->dpm_table.mem_table.dpm_state.hard_min_level;
- PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
- hwmgr, PPSMC_MSG_SetHardMinByFreq,
- (PPCLK_UCLK << 16) | (min_freq & 0xffff))),
- "Failed to set hard min memclk !",
- return ret);
}
if (data->smu_features[GNLD_DPM_UVD].enabled &&
@@ -1739,6 +1799,28 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_
return ret);
}
+ if (data->smu_features[GNLD_DPM_FCLK].enabled &&
+ (feature_mask & FEATURE_DPM_FCLK_MASK)) {
+ min_freq = data->dpm_table.fclk_table.dpm_state.soft_min_level;
+
+ PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
+ hwmgr, PPSMC_MSG_SetSoftMinByFreq,
+ (PPCLK_FCLK << 16) | (min_freq & 0xffff))),
+ "Failed to set soft min fclk!",
+ return ret);
+ }
+
+ if (data->smu_features[GNLD_DPM_DCEFCLK].enabled &&
+ (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
+ min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level;
+
+ PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
+ hwmgr, PPSMC_MSG_SetHardMinByFreq,
+ (PPCLK_DCEFCLK << 16) | (min_freq & 0xffff))),
+ "Failed to set hard min dcefclk!",
+ return ret);
+ }
+
return ret;
}
@@ -1811,6 +1893,17 @@ static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_
return ret);
}
+ if (data->smu_features[GNLD_DPM_FCLK].enabled &&
+ (feature_mask & FEATURE_DPM_FCLK_MASK)) {
+ max_freq = data->dpm_table.fclk_table.dpm_state.soft_max_level;
+
+ PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
+ hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
+ (PPCLK_FCLK << 16) | (max_freq & 0xffff))),
+ "Failed to set soft max fclk!",
+ return ret);
+ }
+
return ret;
}
@@ -1918,16 +2011,36 @@ static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
return (mem_clk * 100);
}
+static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr, SmuMetrics_t *metrics_table)
+{
+ struct vega20_hwmgr *data =
+ (struct vega20_hwmgr *)(hwmgr->backend);
+ int ret = 0;
+
+ if (!data->metrics_time || time_after(jiffies, data->metrics_time + HZ / 2)) {
+ ret = smum_smc_table_manager(hwmgr, (uint8_t *)metrics_table,
+ TABLE_SMU_METRICS, true);
+ if (ret) {
+ pr_info("Failed to export SMU metrics table!\n");
+ return ret;
+ }
+ memcpy(&data->metrics_table, metrics_table, sizeof(SmuMetrics_t));
+ data->metrics_time = jiffies;
+ } else
+ memcpy(metrics_table, &data->metrics_table, sizeof(SmuMetrics_t));
+
+ return ret;
+}
+
static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
uint32_t *query)
{
int ret = 0;
SmuMetrics_t metrics_table;
- ret = smum_smc_table_manager(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS, true);
- PP_ASSERT_WITH_CODE(!ret,
- "Failed to export SMU METRICS table!",
- return ret);
+ ret = vega20_get_metrics_table(hwmgr, &metrics_table);
+ if (ret)
+ return ret;
*query = metrics_table.CurrSocketPower << 8;
@@ -1958,10 +2071,9 @@ static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
int ret = 0;
SmuMetrics_t metrics_table;
- ret = smum_smc_table_manager(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS, true);
- PP_ASSERT_WITH_CODE(!ret,
- "Failed to export SMU METRICS table!",
- return ret);
+ ret = vega20_get_metrics_table(hwmgr, &metrics_table);
+ if (ret)
+ return ret;
*activity_percent = metrics_table.AverageGfxActivity;
@@ -1973,16 +2085,18 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
{
struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
struct amdgpu_device *adev = hwmgr->adev;
+ SmuMetrics_t metrics_table;
uint32_t val_vid;
int ret = 0;
switch (idx) {
case AMDGPU_PP_SENSOR_GFX_SCLK:
- ret = vega20_get_current_clk_freq(hwmgr,
- PPCLK_GFXCLK,
- (uint32_t *)value);
- if (!ret)
- *size = 4;
+ ret = vega20_get_metrics_table(hwmgr, &metrics_table);
+ if (ret)
+ return ret;
+
+ *((uint32_t *)value) = metrics_table.AverageGfxclkFrequency * 100;
+ *size = 4;
break;
case AMDGPU_PP_SENSOR_GFX_MCLK:
ret = vega20_get_current_clk_freq(hwmgr,
@@ -2140,6 +2254,12 @@ static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
data->dpm_table.mem_table.dpm_state.soft_max_level =
data->dpm_table.mem_table.dpm_levels[soft_level].value;
+ soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
+
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->dpm_table.soc_table.dpm_levels[soft_level].value;
+
ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
PP_ASSERT_WITH_CODE(!ret,
"Failed to upload boot level to highest!",
@@ -2172,6 +2292,12 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
data->dpm_table.mem_table.dpm_state.soft_max_level =
data->dpm_table.mem_table.dpm_levels[soft_level].value;
+ soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
+
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->dpm_table.soc_table.dpm_levels[soft_level].value;
+
ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
PP_ASSERT_WITH_CODE(!ret,
"Failed to upload boot level to highest!",
@@ -2188,8 +2314,32 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
{
+ struct vega20_hwmgr *data =
+ (struct vega20_hwmgr *)(hwmgr->backend);
+ uint32_t soft_min_level, soft_max_level;
int ret = 0;
+ soft_min_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
+ soft_max_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
+ data->dpm_table.gfx_table.dpm_state.soft_min_level =
+ data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.gfx_table.dpm_state.soft_max_level =
+ data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
+
+ soft_min_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
+ soft_max_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
+ data->dpm_table.mem_table.dpm_state.soft_min_level =
+ data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.mem_table.dpm_state.soft_max_level =
+ data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
+
+ soft_min_level = vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
+ soft_max_level = vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
+
ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
PP_ASSERT_WITH_CODE(!ret,
"Failed to upload DPM Bootup Levels!",
@@ -2240,7 +2390,7 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, uint32_t mask)
{
struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
- uint32_t soft_min_level, soft_max_level;
+ uint32_t soft_min_level, soft_max_level, hard_min_level;
int ret = 0;
switch (type) {
@@ -2248,6 +2398,13 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
soft_min_level = mask ? (ffs(mask) - 1) : 0;
soft_max_level = mask ? (fls(mask) - 1) : 0;
+ if (soft_max_level >= data->dpm_table.gfx_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ soft_max_level,
+ data->dpm_table.gfx_table.count - 1);
+ return -EINVAL;
+ }
+
data->dpm_table.gfx_table.dpm_state.soft_min_level =
data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
data->dpm_table.gfx_table.dpm_state.soft_max_level =
@@ -2268,6 +2425,13 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
soft_min_level = mask ? (ffs(mask) - 1) : 0;
soft_max_level = mask ? (fls(mask) - 1) : 0;
+ if (soft_max_level >= data->dpm_table.mem_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ soft_max_level,
+ data->dpm_table.mem_table.count - 1);
+ return -EINVAL;
+ }
+
data->dpm_table.mem_table.dpm_state.soft_min_level =
data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
data->dpm_table.mem_table.dpm_state.soft_max_level =
@@ -2285,6 +2449,84 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
break;
+ case PP_SOCCLK:
+ soft_min_level = mask ? (ffs(mask) - 1) : 0;
+ soft_max_level = mask ? (fls(mask) - 1) : 0;
+
+ if (soft_max_level >= data->dpm_table.soc_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ soft_max_level,
+ data->dpm_table.soc_table.count - 1);
+ return -EINVAL;
+ }
+
+ data->dpm_table.soc_table.dpm_state.soft_min_level =
+ data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.soc_table.dpm_state.soft_max_level =
+ data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
+
+ ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload boot level to lowest!",
+ return ret);
+
+ ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload dpm max level to highest!",
+ return ret);
+
+ break;
+
+ case PP_FCLK:
+ soft_min_level = mask ? (ffs(mask) - 1) : 0;
+ soft_max_level = mask ? (fls(mask) - 1) : 0;
+
+ if (soft_max_level >= data->dpm_table.fclk_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ soft_max_level,
+ data->dpm_table.fclk_table.count - 1);
+ return -EINVAL;
+ }
+
+ data->dpm_table.fclk_table.dpm_state.soft_min_level =
+ data->dpm_table.fclk_table.dpm_levels[soft_min_level].value;
+ data->dpm_table.fclk_table.dpm_state.soft_max_level =
+ data->dpm_table.fclk_table.dpm_levels[soft_max_level].value;
+
+ ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_FCLK_MASK);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload boot level to lowest!",
+ return ret);
+
+ ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_FCLK_MASK);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload dpm max level to highest!",
+ return ret);
+
+ break;
+
+ case PP_DCEFCLK:
+ hard_min_level = mask ? (ffs(mask) - 1) : 0;
+
+ if (hard_min_level >= data->dpm_table.dcef_table.count) {
+ pr_err("Clock level specified %d is over max allowed %d\n",
+ hard_min_level,
+ data->dpm_table.dcef_table.count - 1);
+ return -EINVAL;
+ }
+
+ data->dpm_table.dcef_table.dpm_state.hard_min_level =
+ data->dpm_table.dcef_table.dpm_levels[hard_min_level].value;
+
+ ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_DCEFCLK_MASK);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Failed to upload boot level to lowest!",
+ return ret);
+
+ //TODO: Setting DCEFCLK max dpm level is not supported
+
+ break;
+
case PP_PCIE:
soft_min_level = mask ? (ffs(mask) - 1) : 0;
soft_max_level = mask ? (fls(mask) - 1) : 0;
@@ -2335,6 +2577,7 @@ static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
return ret;
vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
+ vega20_force_clock_level(hwmgr, PP_SOCCLK, 1 << soc_mask);
break;
case AMD_DPM_FORCED_LEVEL_MANUAL:
@@ -2765,6 +3008,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
return 0;
}
+static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+{
+ static const char *ppfeature_name[] = {
+ "DPM_PREFETCHER",
+ "GFXCLK_DPM",
+ "UCLK_DPM",
+ "SOCCLK_DPM",
+ "UVD_DPM",
+ "VCE_DPM",
+ "ULV",
+ "MP0CLK_DPM",
+ "LINK_DPM",
+ "DCEFCLK_DPM",
+ "GFXCLK_DS",
+ "SOCCLK_DS",
+ "LCLK_DS",
+ "PPT",
+ "TDC",
+ "THERMAL",
+ "GFX_PER_CU_CG",
+ "RM",
+ "DCEFCLK_DS",
+ "ACDC",
+ "VR0HOT",
+ "VR1HOT",
+ "FW_CTF",
+ "LED_DISPLAY",
+ "FAN_CONTROL",
+ "GFX_EDC",
+ "GFXOFF",
+ "CG",
+ "FCLK_DPM",
+ "FCLK_DS",
+ "MP1CLK_DS",
+ "MP0CLK_DS",
+ "XGMI"};
+ static const char *output_title[] = {
+ "FEATURES",
+ "BITMASK",
+ "ENABLEMENT"};
+ uint64_t features_enabled;
+ int i;
+ int ret = 0;
+ int size = 0;
+
+ ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+ return ret);
+
+ size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled);
+ size += sprintf(buf + size, "%-19s %-22s %s\n",
+ output_title[0],
+ output_title[1],
+ output_title[2]);
+ for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+ size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
+ ppfeature_name[i],
+ 1ULL << i,
+ (features_enabled & (1ULL << i)) ? "Y" : "N");
+ }
+
+ return size;
+}
+
+static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
+{
+ uint64_t features_enabled;
+ uint64_t features_to_enable;
+ uint64_t features_to_disable;
+ int ret = 0;
+
+ if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
+ return -EINVAL;
+
+ ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+ if (ret)
+ return ret;
+
+ features_to_disable =
+ (features_enabled ^ new_ppfeature_masks) & features_enabled;
+ features_to_enable =
+ (features_enabled ^ new_ppfeature_masks) ^ features_to_disable;
+
+ pr_debug("features_to_disable 0x%llx\n", features_to_disable);
+ pr_debug("features_to_enable 0x%llx\n", features_to_enable);
+
+ if (features_to_disable) {
+ ret = vega20_enable_smc_features(hwmgr, false, features_to_disable);
+ if (ret)
+ return ret;
+ }
+
+ if (features_to_enable) {
+ ret = vega20_enable_smc_features(hwmgr, true, features_to_enable);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, char *buf)
{
@@ -2779,6 +3124,8 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
struct amdgpu_device *adev = hwmgr->adev;
struct pp_clock_levels_with_latency clocks;
+ struct vega20_single_dpm_table *fclk_dpm_table =
+ &(data->dpm_table.fclk_table);
int i, now, size = 0;
int ret = 0;
uint32_t gen_speed, lane_width;
@@ -2818,6 +3165,52 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
(clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
break;
+ case PP_SOCCLK:
+ ret = vega20_get_current_clk_freq(hwmgr, PPCLK_SOCCLK, &now);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Attempt to get current socclk freq Failed!",
+ return ret);
+
+ ret = vega20_get_socclocks(hwmgr, &clocks);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Attempt to get soc clk levels Failed!",
+ return ret);
+
+ for (i = 0; i < clocks.num_levels; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+
+ case PP_FCLK:
+ ret = vega20_get_current_clk_freq(hwmgr, PPCLK_FCLK, &now);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Attempt to get current fclk freq Failed!",
+ return ret);
+
+ for (i = 0; i < fclk_dpm_table->count; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, fclk_dpm_table->dpm_levels[i].value,
+ fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
+ break;
+
+ case PP_DCEFCLK:
+ ret = vega20_get_current_clk_freq(hwmgr, PPCLK_DCEFCLK, &now);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Attempt to get current dcefclk freq Failed!",
+ return ret);
+
+ ret = vega20_get_dcefclocks(hwmgr, &clocks);
+ PP_ASSERT_WITH_CODE(!ret,
+ "Attempt to get dcefclk levels Failed!",
+ return ret);
+
+ for (i = 0; i < clocks.num_levels; i++)
+ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+
case PP_PCIE:
gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
@@ -3261,6 +3654,9 @@ static int conv_power_profile_to_pplib_workload(int power_profile)
int pplib_workload = 0;
switch (power_profile) {
+ case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT:
+ pplib_workload = WORKLOAD_DEFAULT_BIT;
+ break;
case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
break;
@@ -3290,6 +3686,7 @@ static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
uint32_t i, size = 0;
uint16_t workload_type = 0;
static const char *profile_name[] = {
+ "BOOTUP_DEFAULT",
"3D_FULL_SCREEN",
"POWER_SAVING",
"VIDEO",
@@ -3557,6 +3954,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
.force_clock_level = vega20_force_clock_level,
.print_clock_levels = vega20_print_clock_levels,
.read_sensor = vega20_read_sensor,
+ .get_ppfeature_status = vega20_get_ppfeature_status,
+ .set_ppfeature_status = vega20_set_ppfeature_status,
/* powergate related */
.powergate_uvd = vega20_power_gate_uvd,
.powergate_vce = vega20_power_gate_vce,
@@ -3577,6 +3976,10 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
/* smu memory related */
.notify_cac_buffer_info = vega20_notify_cac_buffer_info,
.enable_mgpu_fan_boost = vega20_enable_mgpu_fan_boost,
+ /* BACO related */
+ .get_asic_baco_capability = vega20_baco_get_capability,
+ .get_asic_baco_state = vega20_baco_get_state,
+ .set_asic_baco_state = vega20_baco_set_state,
};
int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
index 25faaa5c5b10..37f5f5e657da 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
@@ -520,6 +520,9 @@ struct vega20_hwmgr {
/* ---- Gfxoff ---- */
bool gfxoff_allowed;
uint32_t counter_gfxoff;
+
+ unsigned long metrics_time;
+ SmuMetrics_t metrics_table;
};
#define VEGA20_DPM2_NEAR_TDP_DEC 10
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h
index 6738bad53602..613cb1989b3d 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h
@@ -31,5 +31,6 @@
#include "asic_reg/mp/mp_9_0_sh_mask.h"
#include "asic_reg/nbio/nbio_7_4_offset.h"
+#include "asic_reg/nbio/nbio_7_4_sh_mask.h"
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
index f4dab979a3a1..6e0be6027705 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
@@ -397,7 +397,6 @@ struct phm_odn_clock_levels {
};
extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr);
-extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
index 0d298a0409f5..bac3d85e3b82 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -47,6 +47,11 @@ enum DISPLAY_GAP {
};
typedef enum DISPLAY_GAP DISPLAY_GAP;
+enum BACO_STATE {
+ BACO_STATE_OUT = 0,
+ BACO_STATE_IN,
+};
+
struct vi_dpm_level {
bool enabled;
uint32_t value;
@@ -251,7 +256,6 @@ struct pp_hwmgr_func {
uint32_t (*get_sclk)(struct pp_hwmgr *hwmgr, bool low);
int (*power_state_set)(struct pp_hwmgr *hwmgr,
const void *state);
- int (*enable_clock_power_gating)(struct pp_hwmgr *hwmgr);
int (*notify_smc_display_config_after_ps_adjustment)(struct pp_hwmgr *hwmgr);
int (*pre_display_config_changed)(struct pp_hwmgr *hwmgr);
int (*display_config_changed)(struct pp_hwmgr *hwmgr);
@@ -334,6 +338,11 @@ struct pp_hwmgr_func {
int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr);
int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
+ int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap);
+ int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);
+ int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state);
+ int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf);
+ int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t ppfeature_masks);
};
struct pp_table_func {
@@ -678,6 +687,7 @@ struct pp_advance_fan_control_parameters {
uint32_t ulTargetGfxClk;
uint16_t usZeroRPMStartTemperature;
uint16_t usZeroRPMStopTemperature;
+ uint16_t usMGpuThrottlingRPMLimit;
};
struct pp_thermal_controller_info {
@@ -705,7 +715,7 @@ enum PP_TABLE_VERSION {
/**
* The main hardware manager structure.
*/
-#define Workload_Policy_Max 5
+#define Workload_Policy_Max 6
struct pp_hwmgr {
void *adev;
diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c
index 155ab177ce0b..73e508e00e30 100644
--- a/drivers/gpu/drm/arc/arcpgu_crtc.c
+++ b/drivers/gpu/drm/arc/arcpgu_crtc.c
@@ -15,12 +15,12 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_vblank.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/platform_data/simplefb.h>
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
index 39a79f5718c4..c9f78397d345 100644
--- a/drivers/gpu/drm/arc/arcpgu_drv.c
+++ b/drivers/gpu/drm/arc/arcpgu_drv.c
@@ -15,15 +15,15 @@
*/
#include <linux/clk.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_device.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
+#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/of_reserved_mem.h>
diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c
index 6530d88f7293..5ea053cf805c 100644
--- a/drivers/gpu/drm/arc/arcpgu_sim.c
+++ b/drivers/gpu/drm/arc/arcpgu_sim.c
@@ -14,8 +14,9 @@
*
*/
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_probe_helper.h>
#include "arcpgu.h"
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index 9a18e1bd57b4..a204103b3efb 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -1,13 +1,10 @@
-config DRM_ARM
- bool
- help
- Choose this option to select drivers for ARM's devices
+# SPDX-License-Identifier: GPL-2.0
+menu "ARM devices"
config DRM_HDLCD
tristate "ARM HDLCD"
depends on DRM && OF && (ARM || ARM64)
depends on COMMON_CLK
- select DRM_ARM
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
help
@@ -29,7 +26,6 @@ config DRM_MALI_DISPLAY
tristate "ARM Mali Display Processor"
depends on DRM && OF && (ARM || ARM64)
depends on COMMON_CLK
- select DRM_ARM
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
@@ -40,3 +36,7 @@ config DRM_MALI_DISPLAY
of the hardware.
If compiled as a module it will be called mali-dp.
+
+source "drivers/gpu/drm/arm/display/Kconfig"
+
+endmenu
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index 3bf31d1a4722..120bef801fcf 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
mali-dp-y += malidp_mw.o
obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
+obj-$(CONFIG_DRM_KOMEDA) += display/
diff --git a/drivers/gpu/drm/arm/display/Kbuild b/drivers/gpu/drm/arm/display/Kbuild
new file mode 100644
index 000000000000..382f1ca831e4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kbuild
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DRM_KOMEDA) += komeda/
diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig
new file mode 100644
index 000000000000..cec0639e3aa1
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+config DRM_KOMEDA
+ tristate "ARM Komeda display driver"
+ depends on DRM && OF
+ depends on COMMON_CLK
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
+ select VIDEOMODE_HELPERS
+ help
+ Choose this option if you want to compile the ARM Komeda display
+ Processor driver. It supports the D71 variants of the hardware.
+
+ If compiled as a module it will be called komeda.
diff --git a/drivers/gpu/drm/arm/display/include/malidp_io.h b/drivers/gpu/drm/arm/display/include/malidp_io.h
new file mode 100644
index 000000000000..4fb3caf864ce
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_io.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _MALIDP_IO_H_
+#define _MALIDP_IO_H_
+
+#include <linux/io.h>
+
+static inline u32
+malidp_read32(u32 __iomem *base, u32 offset)
+{
+ return readl((base + (offset >> 2)));
+}
+
+static inline void
+malidp_write32(u32 __iomem *base, u32 offset, u32 v)
+{
+ writel(v, (base + (offset >> 2)));
+}
+
+static inline void
+malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
+{
+ u32 tmp = malidp_read32(base, offset);
+
+ tmp &= (~m);
+ malidp_write32(base, offset, v | tmp);
+}
+
+static inline void
+malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ malidp_write32(base, offset + i * 4, values[i]);
+}
+
+#endif /*_MALIDP_IO_H_*/
diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h
new file mode 100644
index 000000000000..b35fc5db866b
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_product.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _MALIDP_PRODUCT_H_
+#define _MALIDP_PRODUCT_H_
+
+/* Product identification */
+#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
+ ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
+ (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
+
+#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
+#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
+#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
+#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
+
+/* Mali-display product IDs */
+#define MALIDP_D71_PRODUCT_ID 0x0071
+
+#endif /* _MALIDP_PRODUCT_H_ */
diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
new file mode 100644
index 000000000000..63cc47cefcf8
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _MALIDP_UTILS_
+#define _MALIDP_UTILS_
+
+#define has_bit(nr, mask) (BIT(nr) & (mask))
+#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
+
+#define dp_for_each_set_bit(bit, mask) \
+ for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
+
+#endif /* _MALIDP_UTILS_ */
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
new file mode 100644
index 000000000000..1b875e5dc0f6
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-y := \
+ -I$(src)/../include \
+ -I$(src)
+
+komeda-y := \
+ komeda_drv.o \
+ komeda_dev.o \
+ komeda_format_caps.o \
+ komeda_pipeline.o \
+ komeda_framebuffer.o \
+ komeda_kms.o \
+ komeda_crtc.o \
+ komeda_plane.o \
+ komeda_private_obj.o
+
+komeda-y += \
+ d71/d71_dev.o
+
+obj-$(CONFIG_DRM_KOMEDA) += komeda.o
diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
new file mode 100644
index 000000000000..edbf9daa1545
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include "malidp_io.h"
+#include "komeda_dev.h"
+
+static int d71_enum_resources(struct komeda_dev *mdev)
+{
+ /* TODO add enum resources */
+ return -1;
+}
+
+#define __HW_ID(__group, __format) \
+ ((((__group) & 0x7) << 3) | ((__format) & 0x7))
+
+#define RICH KOMEDA_FMT_RICH_LAYER
+#define SIMPLE KOMEDA_FMT_SIMPLE_LAYER
+#define RICH_SIMPLE (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)
+#define RICH_WB (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)
+#define RICH_SIMPLE_WB (RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)
+
+#define Rot_0 DRM_MODE_ROTATE_0
+#define Flip_H_V (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)
+#define Rot_ALL_H_V (DRM_MODE_ROTATE_MASK | Flip_H_V)
+
+#define LYT_NM BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
+#define LYT_WB BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
+#define LYT_NM_WB (LYT_NM | LYT_WB)
+
+#define AFB_TH AFBC(_TILED | _SPARSE)
+#define AFB_TH_SC_YTR AFBC(_TILED | _SC | _SPARSE | _YTR)
+#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)
+
+static struct komeda_format_caps d71_format_caps_table[] = {
+ /* HW_ID | fourcc | tile_sz | layer_types | rots | afbc_layouts | afbc_features */
+ /* ABGR_2101010*/
+ {__HW_ID(0, 0), DRM_FORMAT_ARGB2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ {__HW_ID(0, 2), DRM_FORMAT_RGBA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 3), DRM_FORMAT_BGRA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* ABGR_8888*/
+ {__HW_ID(1, 0), DRM_FORMAT_ARGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ {__HW_ID(1, 2), DRM_FORMAT_RGBA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 3), DRM_FORMAT_BGRA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* XBGB_8888 */
+ {__HW_ID(2, 0), DRM_FORMAT_XRGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 1), DRM_FORMAT_XBGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 2), DRM_FORMAT_RGBX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 3), DRM_FORMAT_BGRX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */
+ {__HW_ID(3, 0), DRM_FORMAT_RGB888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
+ {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
+ {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ /* BGR 16bpp */
+ {__HW_ID(4, 0), DRM_FORMAT_RGBA5551, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
+ {__HW_ID(4, 2), DRM_FORMAT_RGB565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
+ {__HW_ID(4, 4), DRM_FORMAT_R8, 1, SIMPLE, Rot_0, 0, 0},
+ /* YUV 444/422/420 8bit */
+ {__HW_ID(5, 0), 0 /*XYUV8888*/, 1, 0, 0, 0, 0},
+ /* XYUV unsupported*/
+ {__HW_ID(5, 1), DRM_FORMAT_YUYV, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
+ {__HW_ID(5, 2), DRM_FORMAT_YUYV, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 3), DRM_FORMAT_UYVY, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 4), 0, /*X0L0 */ 2, 0, 0, 0}, /* Y0L0 unsupported */
+ {__HW_ID(5, 6), DRM_FORMAT_NV12, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 6), 0/*DRM_FORMAT_YUV420_8BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
+ {__HW_ID(5, 7), DRM_FORMAT_YUV420, 1, RICH, Flip_H_V, 0, 0},
+ /* YUV 10bit*/
+ {__HW_ID(6, 0), 0,/*XVYU2101010*/ 1, 0, 0, 0, 0},/* VYV30 unsupported */
+ {__HW_ID(6, 6), 0/*DRM_FORMAT_X0L2*/, 2, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(6, 7), 0/*DRM_FORMAT_P010*/, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(6, 7), 0/*DRM_FORMAT_YUV420_10BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH},
+};
+
+static void d71_init_fmt_tbl(struct komeda_dev *mdev)
+{
+ struct komeda_format_caps_table *table = &mdev->fmt_tbl;
+
+ table->format_caps = d71_format_caps_table;
+ table->n_formats = ARRAY_SIZE(d71_format_caps_table);
+}
+
+static struct komeda_dev_funcs d71_chip_funcs = {
+ .init_format_table = d71_init_fmt_tbl,
+ .enum_resources = d71_enum_resources,
+ .cleanup = NULL,
+};
+
+#define GLB_ARCH_ID 0x000
+#define GLB_CORE_ID 0x004
+#define GLB_CORE_INFO 0x008
+
+struct komeda_dev_funcs *
+d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
+{
+ chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
+ chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
+ chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
+
+ return &d71_chip_funcs;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
new file mode 100644
index 000000000000..3ca5718aa0c2
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
+
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
+};
+
+static const struct drm_crtc_funcs komeda_crtc_funcs = {
+};
+
+int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct komeda_crtc *crtc;
+ struct komeda_pipeline *master;
+ char str[16];
+ int i;
+
+ kms->n_crtcs = 0;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ crtc = &kms->crtcs[kms->n_crtcs];
+ master = mdev->pipelines[i];
+
+ crtc->master = master;
+ crtc->slave = NULL;
+
+ if (crtc->slave)
+ sprintf(str, "pipe-%d", crtc->slave->id);
+ else
+ sprintf(str, "None");
+
+ DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
+ kms->n_crtcs, master->id, str,
+ master->of_output_dev ?
+ master->of_output_dev->full_name : "None");
+
+ kms->n_crtcs++;
+ }
+
+ return 0;
+}
+
+static struct drm_plane *
+get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
+{
+ struct komeda_plane *kplane;
+ struct drm_plane *plane;
+
+ drm_for_each_plane(plane, &kms->base) {
+ if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+ continue;
+
+ kplane = to_kplane(plane);
+ /* only master can be primary */
+ if (kplane->layer->base.pipeline == crtc->master)
+ return plane;
+ }
+
+ return NULL;
+}
+
+static int komeda_crtc_add(struct komeda_kms_dev *kms,
+ struct komeda_crtc *kcrtc)
+{
+ struct drm_crtc *crtc = &kcrtc->base;
+ int err;
+
+ err = drm_crtc_init_with_planes(&kms->base, crtc,
+ get_crtc_primary(kms, kcrtc), NULL,
+ &komeda_crtc_funcs, NULL);
+ if (err)
+ return err;
+
+ drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
+ drm_crtc_vblank_reset(crtc);
+
+ crtc->port = kcrtc->master->of_output_port;
+
+ return 0;
+}
+
+int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
+{
+ int i, err;
+
+ for (i = 0; i < kms->n_crtcs; i++) {
+ err = komeda_crtc_add(kms, &kms->crtcs[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
new file mode 100644
index 000000000000..70e9bb7fa30c
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_print.h>
+
+#include "komeda_dev.h"
+
+static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
+{
+ struct komeda_pipeline *pipe;
+ struct clk *clk;
+ u32 pipe_id;
+ int ret = 0;
+
+ ret = of_property_read_u32(np, "reg", &pipe_id);
+ if (ret != 0 || pipe_id >= mdev->n_pipelines)
+ return -EINVAL;
+
+ pipe = mdev->pipelines[pipe_id];
+
+ clk = of_clk_get_by_name(np, "aclk");
+ if (IS_ERR(clk)) {
+ DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id);
+ return PTR_ERR(clk);
+ }
+ pipe->aclk = clk;
+
+ clk = of_clk_get_by_name(np, "pxclk");
+ if (IS_ERR(clk)) {
+ DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id);
+ return PTR_ERR(clk);
+ }
+ pipe->pxlclk = clk;
+
+ /* enum ports */
+ pipe->of_output_dev =
+ of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
+ pipe->of_output_port =
+ of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
+
+ pipe->of_node = np;
+
+ return 0;
+}
+
+static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
+{
+ struct device_node *child, *np = dev->of_node;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ mdev->mclk = clk;
+
+ for_each_available_child_of_node(np, child) {
+ if (of_node_cmp(child->name, "pipeline") == 0) {
+ ret = komeda_parse_pipe_dt(mdev, child);
+ if (ret) {
+ DRM_ERROR("parse pipeline dt error!\n");
+ of_node_put(child);
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+struct komeda_dev *komeda_dev_create(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct komeda_product_data *product;
+ struct komeda_dev *mdev;
+ struct resource *io_res;
+ int err = 0;
+
+ product = of_device_get_match_data(dev);
+ if (!product)
+ return ERR_PTR(-ENODEV);
+
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!io_res) {
+ DRM_ERROR("No registers defined.\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return ERR_PTR(-ENOMEM);
+
+ mdev->dev = dev;
+ mdev->reg_base = devm_ioremap_resource(dev, io_res);
+ if (IS_ERR(mdev->reg_base)) {
+ DRM_ERROR("Map register space failed.\n");
+ err = PTR_ERR(mdev->reg_base);
+ mdev->reg_base = NULL;
+ goto err_cleanup;
+ }
+
+ mdev->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(mdev->pclk)) {
+ DRM_ERROR("Get APB clk failed.\n");
+ err = PTR_ERR(mdev->pclk);
+ mdev->pclk = NULL;
+ goto err_cleanup;
+ }
+
+ /* Enable APB clock to access the registers */
+ clk_prepare_enable(mdev->pclk);
+
+ mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
+ if (!komeda_product_match(mdev, product->product_id)) {
+ DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
+ product->product_id,
+ MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
+ err = -ENODEV;
+ goto err_cleanup;
+ }
+
+ DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
+ MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
+ MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
+ MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
+
+ mdev->funcs->init_format_table(mdev);
+
+ err = mdev->funcs->enum_resources(mdev);
+ if (err) {
+ DRM_ERROR("enumerate display resource failed.\n");
+ goto err_cleanup;
+ }
+
+ err = komeda_parse_dt(dev, mdev);
+ if (err) {
+ DRM_ERROR("parse device tree failed.\n");
+ goto err_cleanup;
+ }
+
+ return mdev;
+
+err_cleanup:
+ komeda_dev_destroy(mdev);
+ return ERR_PTR(err);
+}
+
+void komeda_dev_destroy(struct komeda_dev *mdev)
+{
+ struct device *dev = mdev->dev;
+ struct komeda_dev_funcs *funcs = mdev->funcs;
+ int i;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
+ mdev->pipelines[i] = NULL;
+ }
+
+ mdev->n_pipelines = 0;
+
+ if (funcs && funcs->cleanup)
+ funcs->cleanup(mdev);
+
+ if (mdev->reg_base) {
+ devm_iounmap(dev, mdev->reg_base);
+ mdev->reg_base = NULL;
+ }
+
+ if (mdev->mclk) {
+ devm_clk_put(dev, mdev->mclk);
+ mdev->mclk = NULL;
+ }
+
+ if (mdev->pclk) {
+ clk_disable_unprepare(mdev->pclk);
+ devm_clk_put(dev, mdev->pclk);
+ mdev->pclk = NULL;
+ }
+
+ devm_kfree(dev, mdev);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
new file mode 100644
index 000000000000..0f77dead6a23
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _KOMEDA_DEV_H_
+#define _KOMEDA_DEV_H_
+
+#include <linux/device.h>
+#include <linux/clk.h>
+#include "komeda_pipeline.h"
+#include "malidp_product.h"
+#include "komeda_format_caps.h"
+
+/* malidp device id */
+enum {
+ MALI_D71 = 0,
+};
+
+/* pipeline DT ports */
+enum {
+ KOMEDA_OF_PORT_OUTPUT = 0,
+ KOMEDA_OF_PORT_COPROC = 1,
+};
+
+struct komeda_chip_info {
+ u32 arch_id;
+ u32 core_id;
+ u32 core_info;
+ u32 bus_width;
+};
+
+struct komeda_product_data {
+ u32 product_id;
+ struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
+ struct komeda_chip_info *info);
+};
+
+struct komeda_dev;
+
+/**
+ * struct komeda_dev_funcs
+ *
+ * Supplied by chip level and returned by the chip entry function xxx_identify,
+ */
+struct komeda_dev_funcs {
+ /**
+ * @init_format_table:
+ *
+ * initialize &komeda_dev->format_table, this function should be called
+ * before the &enum_resource
+ */
+ void (*init_format_table)(struct komeda_dev *mdev);
+ /**
+ * @enum_resources:
+ *
+ * for CHIP to report or add pipeline and component resources to CORE
+ */
+ int (*enum_resources)(struct komeda_dev *mdev);
+ /** @cleanup: call to chip to cleanup komeda_dev->chip data */
+ void (*cleanup)(struct komeda_dev *mdev);
+};
+
+/**
+ * struct komeda_dev
+ *
+ * Pipeline and component are used to describe how to handle the pixel data.
+ * komeda_device is for describing the whole view of the device, and the
+ * control-abilites of device.
+ */
+struct komeda_dev {
+ struct device *dev;
+ u32 __iomem *reg_base;
+
+ struct komeda_chip_info chip;
+ /** @fmt_tbl: initialized by &komeda_dev_funcs->init_format_table */
+ struct komeda_format_caps_table fmt_tbl;
+ /** @pclk: APB clock for register access */
+ struct clk *pclk;
+ /** @mck: HW main engine clk */
+ struct clk *mclk;
+
+ int n_pipelines;
+ struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
+
+ /** @funcs: chip funcs to access to HW */
+ struct komeda_dev_funcs *funcs;
+ /**
+ * @chip_data:
+ *
+ * chip data will be added by &komeda_dev_funcs.enum_resources() and
+ * destroyed by &komeda_dev_funcs.cleanup()
+ */
+ void *chip_data;
+};
+
+static inline bool
+komeda_product_match(struct komeda_dev *mdev, u32 target)
+{
+ return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
+}
+
+struct komeda_dev_funcs *
+d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
+
+struct komeda_dev *komeda_dev_create(struct device *dev);
+void komeda_dev_destroy(struct komeda_dev *mdev);
+
+#endif /*_KOMEDA_DEV_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
new file mode 100644
index 000000000000..2bdd189b041d
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+struct komeda_drv {
+ struct komeda_dev *mdev;
+ struct komeda_kms_dev *kms;
+};
+
+static void komeda_unbind(struct device *dev)
+{
+ struct komeda_drv *mdrv = dev_get_drvdata(dev);
+
+ if (!mdrv)
+ return;
+
+ komeda_kms_detach(mdrv->kms);
+ komeda_dev_destroy(mdrv->mdev);
+
+ dev_set_drvdata(dev, NULL);
+ devm_kfree(dev, mdrv);
+}
+
+static int komeda_bind(struct device *dev)
+{
+ struct komeda_drv *mdrv;
+ int err;
+
+ mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
+ if (!mdrv)
+ return -ENOMEM;
+
+ mdrv->mdev = komeda_dev_create(dev);
+ if (IS_ERR(mdrv->mdev)) {
+ err = PTR_ERR(mdrv->mdev);
+ goto free_mdrv;
+ }
+
+ mdrv->kms = komeda_kms_attach(mdrv->mdev);
+ if (IS_ERR(mdrv->kms)) {
+ err = PTR_ERR(mdrv->kms);
+ goto destroy_mdev;
+ }
+
+ dev_set_drvdata(dev, mdrv);
+
+ return 0;
+
+destroy_mdev:
+ komeda_dev_destroy(mdrv->mdev);
+
+free_mdrv:
+ devm_kfree(dev, mdrv);
+ return err;
+}
+
+static const struct component_master_ops komeda_master_ops = {
+ .bind = komeda_bind,
+ .unbind = komeda_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static void komeda_add_slave(struct device *master,
+ struct component_match **match,
+ struct device_node *np, int port)
+{
+ struct device_node *remote;
+
+ remote = of_graph_get_remote_node(np, port, 0);
+ if (remote) {
+ drm_of_component_match_add(master, match, compare_of, remote);
+ of_node_put(remote);
+ }
+}
+
+static int komeda_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct component_match *match = NULL;
+ struct device_node *child;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ for_each_available_child_of_node(dev->of_node, child) {
+ if (of_node_cmp(child->name, "pipeline") != 0)
+ continue;
+
+ /* add connector */
+ komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
+ }
+
+ return component_master_add_with_match(dev, &komeda_master_ops, match);
+}
+
+static int komeda_platform_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &komeda_master_ops);
+ return 0;
+}
+
+static const struct komeda_product_data komeda_products[] = {
+ [MALI_D71] = {
+ .product_id = MALIDP_D71_PRODUCT_ID,
+ .identify = d71_identify,
+ },
+};
+
+const struct of_device_id komeda_of_match[] = {
+ { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, komeda_of_match);
+
+static struct platform_driver komeda_platform_driver = {
+ .probe = komeda_platform_probe,
+ .remove = komeda_platform_remove,
+ .driver = {
+ .name = "komeda",
+ .of_match_table = komeda_of_match,
+ .pm = NULL,
+ },
+};
+
+module_platform_driver(komeda_platform_driver);
+
+MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
+MODULE_DESCRIPTION("Komeda KMS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
new file mode 100644
index 000000000000..1e17bd6107a4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+
+#include <linux/slab.h>
+#include "komeda_format_caps.h"
+#include "malidp_utils.h"
+
+const struct komeda_format_caps *
+komeda_get_format_caps(struct komeda_format_caps_table *table,
+ u32 fourcc, u64 modifier)
+{
+ const struct komeda_format_caps *caps;
+ u64 afbc_features = modifier & ~(AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
+ u32 afbc_layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
+ int id;
+
+ for (id = 0; id < table->n_formats; id++) {
+ caps = &table->format_caps[id];
+
+ if (fourcc != caps->fourcc)
+ continue;
+
+ if ((modifier == 0ULL) && (caps->supported_afbc_layouts == 0))
+ return caps;
+
+ if (has_bits(afbc_features, caps->supported_afbc_features) &&
+ has_bit(afbc_layout, caps->supported_afbc_layouts))
+ return caps;
+ }
+
+ return NULL;
+}
+
+u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
+ u32 layer_type, u32 *n_fmts)
+{
+ const struct komeda_format_caps *cap;
+ u32 *fmts;
+ int i, j, n = 0;
+
+ fmts = kcalloc(table->n_formats, sizeof(u32), GFP_KERNEL);
+ if (!fmts)
+ return NULL;
+
+ for (i = 0; i < table->n_formats; i++) {
+ cap = &table->format_caps[i];
+ if (!(layer_type & cap->supported_layer_types) ||
+ (cap->fourcc == 0))
+ continue;
+
+ /* one fourcc may has two caps items in table (afbc/none-afbc),
+ * so check the existing list to avoid adding a duplicated one.
+ */
+ for (j = n - 1; j >= 0; j--)
+ if (fmts[j] == cap->fourcc)
+ break;
+
+ if (j < 0)
+ fmts[n++] = cap->fourcc;
+ }
+
+ if (n_fmts)
+ *n_fmts = n;
+
+ return fmts;
+}
+
+void komeda_put_fourcc_list(u32 *fourcc_list)
+{
+ kfree(fourcc_list);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
new file mode 100644
index 000000000000..60f39e77b098
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+
+#ifndef _KOMEDA_FORMAT_CAPS_H_
+#define _KOMEDA_FORMAT_CAPS_H_
+
+#include <linux/types.h>
+#include <uapi/drm/drm_fourcc.h>
+#include <drm/drm_fourcc.h>
+
+#define AFBC(x) DRM_FORMAT_MOD_ARM_AFBC(x)
+
+/* afbc layerout */
+#define AFBC_16x16(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | (x))
+#define AFBC_32x8(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | (x))
+
+/* afbc features */
+#define _YTR AFBC_FORMAT_MOD_YTR
+#define _SPLIT AFBC_FORMAT_MOD_SPLIT
+#define _SPARSE AFBC_FORMAT_MOD_SPARSE
+#define _CBR AFBC_FORMAT_MOD_CBR
+#define _TILED AFBC_FORMAT_MOD_TILED
+#define _SC AFBC_FORMAT_MOD_SC
+
+/* layer_type */
+#define KOMEDA_FMT_RICH_LAYER BIT(0)
+#define KOMEDA_FMT_SIMPLE_LAYER BIT(1)
+#define KOMEDA_FMT_WB_LAYER BIT(2)
+
+#define AFBC_TH_LAYOUT_ALIGNMENT 8
+#define AFBC_HEADER_SIZE 16
+#define AFBC_SUPERBLK_ALIGNMENT 128
+#define AFBC_SUPERBLK_PIXELS 256
+#define AFBC_BODY_START_ALIGNMENT 1024
+#define AFBC_TH_BODY_START_ALIGNMENT 4096
+
+/**
+ * struct komeda_format_caps
+ *
+ * komeda_format_caps is for describing ARM display specific features and
+ * limitations for a specific format, and format_caps will be linked into
+ * &komeda_framebuffer like a extension of &drm_format_info.
+ *
+ * NOTE: one fourcc may has two different format_caps items for fourcc and
+ * fourcc+modifier
+ *
+ * @hw_id: hw format id, hw specific value.
+ * @fourcc: drm fourcc format.
+ * @tile_size: format tiled size, used by ARM format X0L0/X0L2
+ * @supported_layer_types: indicate which layer supports this format
+ * @supported_rots: allowed rotations for this format
+ * @supported_afbc_layouts: supported afbc layerout
+ * @supported_afbc_features: supported afbc features
+ */
+struct komeda_format_caps {
+ u32 hw_id;
+ u32 fourcc;
+ u32 tile_size;
+ u32 supported_layer_types;
+ u32 supported_rots;
+ u32 supported_afbc_layouts;
+ u64 supported_afbc_features;
+};
+
+/**
+ * struct komeda_format_caps_table - format_caps mananger
+ *
+ * @n_formats: the size of format_caps list.
+ * @format_caps: format_caps list.
+ */
+struct komeda_format_caps_table {
+ u32 n_formats;
+ const struct komeda_format_caps *format_caps;
+};
+
+const struct komeda_format_caps *
+komeda_get_format_caps(struct komeda_format_caps_table *table,
+ u32 fourcc, u64 modifier);
+
+u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
+ u32 layer_type, u32 *n_fmts);
+
+void komeda_put_fourcc_list(u32 *fourcc_list);
+
+#endif
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
new file mode 100644
index 000000000000..9cc9935024f7
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <drm/drm_device.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+#include "komeda_framebuffer.h"
+#include "komeda_dev.h"
+
+static void komeda_fb_destroy(struct drm_framebuffer *fb)
+{
+ struct komeda_fb *kfb = to_kfb(fb);
+ u32 i;
+
+ for (i = 0; i < fb->format->num_planes; i++)
+ drm_gem_object_put_unlocked(fb->obj[i]);
+
+ drm_framebuffer_cleanup(fb);
+ kfree(kfb);
+}
+
+static int komeda_fb_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file, u32 *handle)
+{
+ return drm_gem_handle_create(file, fb->obj[0], handle);
+}
+
+static const struct drm_framebuffer_funcs komeda_fb_funcs = {
+ .destroy = komeda_fb_destroy,
+ .create_handle = komeda_fb_create_handle,
+};
+
+static int
+komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb,
+ struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_framebuffer *fb = &kfb->base;
+ struct drm_gem_object *obj;
+ u32 min_size = 0;
+ u32 i;
+
+ for (i = 0; i < fb->format->num_planes; i++) {
+ obj = drm_gem_object_lookup(file, mode_cmd->handles[i]);
+ if (!obj) {
+ DRM_DEBUG_KMS("Failed to lookup GEM object\n");
+ fb->obj[i] = NULL;
+
+ return -ENOENT;
+ }
+
+ kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1);
+ kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1);
+
+ if (fb->pitches[i] % mdev->chip.bus_width) {
+ DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n",
+ i, fb->pitches[i], mdev->chip.bus_width);
+ drm_gem_object_put_unlocked(obj);
+ fb->obj[i] = NULL;
+
+ return -EINVAL;
+ }
+
+ min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1)
+ * fb->pitches[i])
+ + (kfb->aligned_w * fb->format->cpp[i]
+ * kfb->format_caps->tile_size)
+ + fb->offsets[i];
+
+ if (obj->size < min_size) {
+ DRM_DEBUG_KMS("Fail to check none afbc fb size.\n");
+ drm_gem_object_put_unlocked(obj);
+ fb->obj[i] = NULL;
+
+ return -EINVAL;
+ }
+
+ fb->obj[i] = obj;
+ }
+
+ if (fb->format->num_planes == 3) {
+ if (fb->pitches[1] != fb->pitches[2]) {
+ DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+struct drm_framebuffer *
+komeda_fb_create(struct drm_device *dev, struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct komeda_dev *mdev = dev->dev_private;
+ struct komeda_fb *kfb;
+ int ret = 0, i;
+
+ kfb = kzalloc(sizeof(*kfb), GFP_KERNEL);
+ if (!kfb)
+ return ERR_PTR(-ENOMEM);
+
+ kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0]);
+ if (!kfb->format_caps) {
+ DRM_DEBUG_KMS("FMT %x is not supported.\n",
+ mode_cmd->pixel_format);
+ kfree(kfb);
+ return ERR_PTR(-EINVAL);
+ }
+
+ drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd);
+
+ ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd);
+ if (ret < 0)
+ goto err_cleanup;
+
+ ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs);
+ if (ret < 0) {
+ DRM_DEBUG_KMS("failed to initialize fb\n");
+
+ goto err_cleanup;
+ }
+
+ return &kfb->base;
+
+err_cleanup:
+ for (i = 0; i < kfb->base.format->num_planes; i++)
+ drm_gem_object_put_unlocked(kfb->base.obj[i]);
+
+ kfree(kfb);
+ return ERR_PTR(ret);
+}
+
+dma_addr_t
+komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane)
+{
+ struct drm_framebuffer *fb = &kfb->base;
+ const struct drm_gem_cma_object *obj;
+ u32 plane_x, plane_y, cpp, pitch, offset;
+
+ if (plane >= fb->format->num_planes) {
+ DRM_DEBUG_KMS("Out of max plane num.\n");
+ return -EINVAL;
+ }
+
+ obj = drm_fb_cma_get_gem_obj(fb, plane);
+
+ offset = fb->offsets[plane];
+ if (!fb->modifier) {
+ plane_x = x / (plane ? fb->format->hsub : 1);
+ plane_y = y / (plane ? fb->format->vsub : 1);
+ cpp = fb->format->cpp[plane];
+ pitch = fb->pitches[plane];
+ offset += plane_x * cpp * kfb->format_caps->tile_size +
+ (plane_y * pitch) / kfb->format_caps->tile_size;
+ }
+
+ return obj->paddr + offset;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
new file mode 100644
index 000000000000..0de2e4a2afd2
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _KOMEDA_FRAMEBUFFER_H_
+#define _KOMEDA_FRAMEBUFFER_H_
+
+#include <drm/drm_framebuffer.h>
+#include "komeda_format_caps.h"
+
+/** struct komeda_fb - entend drm_framebuffer with komeda attribute */
+struct komeda_fb {
+ /** @base: &drm_framebuffer */
+ struct drm_framebuffer base;
+ /* @format_caps: &komeda_format_caps */
+ const struct komeda_format_caps *format_caps;
+ /** @aligned_w: aligned frame buffer width */
+ u32 aligned_w;
+ /** @aligned_h: aligned frame buffer height */
+ u32 aligned_h;
+};
+
+#define to_kfb(dfb) container_of(dfb, struct komeda_fb, base)
+
+struct drm_framebuffer *
+komeda_fb_create(struct drm_device *dev, struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd);
+dma_addr_t
+komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane);
+bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type);
+
+#endif
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
new file mode 100644
index 000000000000..47a58ab20434
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <linux/component.h>
+#include <linux/interrupt.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "komeda_dev.h"
+#include "komeda_framebuffer.h"
+#include "komeda_kms.h"
+
+DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
+
+static int komeda_gem_cma_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ u32 alignment = 16; /* TODO get alignment from dev */
+
+ args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
+ alignment);
+
+ return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver komeda_kms_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
+ DRIVER_PRIME,
+ .lastclose = drm_fb_helper_lastclose,
+ .gem_free_object_unlocked = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = komeda_gem_cma_dumb_create,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &komeda_cma_fops,
+ .name = "komeda",
+ .desc = "Arm Komeda Display Processor driver",
+ .date = "20181101",
+ .major = 0,
+ .minor = 1,
+};
+
+static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, old_state);
+
+ drm_atomic_helper_commit_planes(dev, old_state, 0);
+
+ drm_atomic_helper_commit_modeset_enables(dev, old_state);
+
+ drm_atomic_helper_wait_for_flip_done(dev, old_state);
+
+ drm_atomic_helper_commit_hw_done(old_state);
+
+ drm_atomic_helper_cleanup_planes(dev, old_state);
+}
+
+static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
+ .atomic_commit_tail = komeda_kms_commit_tail,
+};
+
+static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
+ .fb_create = komeda_fb_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct drm_mode_config *config = &kms->base.mode_config;
+
+ drm_mode_config_init(&kms->base);
+
+ komeda_kms_setup_crtcs(kms, mdev);
+
+ /* Get value from dev */
+ config->min_width = 0;
+ config->min_height = 0;
+ config->max_width = 4096;
+ config->max_height = 4096;
+ config->allow_fb_modifiers = false;
+
+ config->funcs = &komeda_mode_config_funcs;
+ config->helper_private = &komeda_mode_config_helpers;
+}
+
+struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
+{
+ struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
+ struct drm_device *drm;
+ int err;
+
+ if (!kms)
+ return ERR_PTR(-ENOMEM);
+
+ drm = &kms->base;
+ err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
+ if (err)
+ goto free_kms;
+
+ drm->dev_private = mdev;
+
+ komeda_kms_mode_config_init(kms, mdev);
+
+ err = komeda_kms_add_private_objs(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = komeda_kms_add_planes(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = drm_vblank_init(drm, kms->n_crtcs);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = komeda_kms_add_crtcs(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = component_bind_all(mdev->dev, kms);
+ if (err)
+ goto cleanup_mode_config;
+
+ drm_mode_config_reset(drm);
+
+ err = drm_dev_register(drm, 0);
+ if (err)
+ goto cleanup_mode_config;
+
+ return kms;
+
+cleanup_mode_config:
+ drm_mode_config_cleanup(drm);
+free_kms:
+ kfree(kms);
+ return ERR_PTR(err);
+}
+
+void komeda_kms_detach(struct komeda_kms_dev *kms)
+{
+ struct drm_device *drm = &kms->base;
+ struct komeda_dev *mdev = drm->dev_private;
+
+ drm_dev_unregister(drm);
+ component_unbind_all(mdev->dev, drm);
+ komeda_kms_cleanup_private_objs(mdev);
+ drm_mode_config_cleanup(drm);
+ drm->dev_private = NULL;
+ drm_dev_put(drm);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
new file mode 100644
index 000000000000..874e9c9f0749
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _KOMEDA_KMS_H_
+#define _KOMEDA_KMS_H_
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_writeback.h>
+
+/** struct komeda_plane - komeda instance of drm_plane */
+struct komeda_plane {
+ /** @base: &drm_plane */
+ struct drm_plane base;
+ /**
+ * @layer:
+ *
+ * represents available layer input pipelines for this plane.
+ *
+ * NOTE:
+ * the layer is not for a specific Layer, but indicate a group of
+ * Layers with same capabilities.
+ */
+ struct komeda_layer *layer;
+};
+
+/**
+ * struct komeda_plane_state
+ *
+ * The plane_state can be split into two data flow (left/right) and handled
+ * by two layers &komeda_plane.layer and &komeda_plane.layer.right
+ */
+struct komeda_plane_state {
+ /** @base: &drm_plane_state */
+ struct drm_plane_state base;
+
+ /* private properties */
+};
+
+/**
+ * struct komeda_wb_connector
+ */
+struct komeda_wb_connector {
+ /** @base: &drm_writeback_connector */
+ struct drm_writeback_connector base;
+
+ /** @wb_layer: represents associated writeback pipeline of komeda */
+ struct komeda_layer *wb_layer;
+};
+
+/**
+ * struct komeda_crtc
+ */
+struct komeda_crtc {
+ /** @base: &drm_crtc */
+ struct drm_crtc base;
+ /** @master: only master has display output */
+ struct komeda_pipeline *master;
+ /**
+ * @slave: optional
+ *
+ * Doesn't have its own display output, the handled data flow will
+ * merge into the master.
+ */
+ struct komeda_pipeline *slave;
+};
+
+/** struct komeda_crtc_state */
+struct komeda_crtc_state {
+ /** @base: &drm_crtc_state */
+ struct drm_crtc_state base;
+
+ /* private properties */
+
+ /* computed state which are used by validate/check */
+ u32 affected_pipes;
+ u32 active_pipes;
+};
+
+/** struct komeda_kms_dev - for gather KMS related things */
+struct komeda_kms_dev {
+ /** @base: &drm_device */
+ struct drm_device base;
+
+ /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
+ int n_crtcs;
+ /** @crtcs: crtcs list */
+ struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
+};
+
+#define to_kplane(p) container_of(p, struct komeda_plane, base)
+#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
+#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
+#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
+#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
+#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
+
+int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+
+int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev);
+void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
+
+struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
+void komeda_kms_detach(struct komeda_kms_dev *kms);
+
+#endif /*_KOMEDA_KMS_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
new file mode 100644
index 000000000000..f1908e9ef128
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <drm/drm_print.h>
+
+#include "komeda_dev.h"
+#include "komeda_pipeline.h"
+
+/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
+struct komeda_pipeline *
+komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
+ struct komeda_pipeline_funcs *funcs)
+{
+ struct komeda_pipeline *pipe;
+
+ if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
+ DRM_ERROR("Exceed max support %d pipelines.\n",
+ KOMEDA_MAX_PIPELINES);
+ return NULL;
+ }
+
+ if (size < sizeof(*pipe)) {
+ DRM_ERROR("Request pipeline size too small.\n");
+ return NULL;
+ }
+
+ pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
+ if (!pipe)
+ return NULL;
+
+ pipe->mdev = mdev;
+ pipe->id = mdev->n_pipelines;
+ pipe->funcs = funcs;
+
+ mdev->pipelines[mdev->n_pipelines] = pipe;
+ mdev->n_pipelines++;
+
+ return pipe;
+}
+
+void komeda_pipeline_destroy(struct komeda_dev *mdev,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_component *c;
+ int i;
+
+ dp_for_each_set_bit(i, pipe->avail_comps) {
+ c = komeda_pipeline_get_component(pipe, i);
+ komeda_component_destroy(mdev, c);
+ }
+
+ clk_put(pipe->pxlclk);
+ clk_put(pipe->aclk);
+
+ of_node_put(pipe->of_output_dev);
+ of_node_put(pipe->of_output_port);
+ of_node_put(pipe->of_node);
+
+ devm_kfree(mdev->dev, pipe);
+}
+
+struct komeda_component **
+komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
+{
+ struct komeda_dev *mdev = pipe->mdev;
+ struct komeda_pipeline *temp = NULL;
+ struct komeda_component **pos = NULL;
+
+ switch (id) {
+ case KOMEDA_COMPONENT_LAYER0:
+ case KOMEDA_COMPONENT_LAYER1:
+ case KOMEDA_COMPONENT_LAYER2:
+ case KOMEDA_COMPONENT_LAYER3:
+ pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
+ break;
+ case KOMEDA_COMPONENT_WB_LAYER:
+ pos = to_cpos(pipe->wb_layer);
+ break;
+ case KOMEDA_COMPONENT_COMPIZ0:
+ case KOMEDA_COMPONENT_COMPIZ1:
+ temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
+ if (!temp) {
+ DRM_ERROR("compiz-%d doesn't exist.\n", id);
+ return NULL;
+ }
+ pos = to_cpos(temp->compiz);
+ break;
+ case KOMEDA_COMPONENT_SCALER0:
+ case KOMEDA_COMPONENT_SCALER1:
+ pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
+ break;
+ case KOMEDA_COMPONENT_IPS0:
+ case KOMEDA_COMPONENT_IPS1:
+ temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
+ if (!temp) {
+ DRM_ERROR("ips-%d doesn't exist.\n", id);
+ return NULL;
+ }
+ pos = to_cpos(temp->improc);
+ break;
+ case KOMEDA_COMPONENT_TIMING_CTRLR:
+ pos = to_cpos(pipe->ctrlr);
+ break;
+ default:
+ pos = NULL;
+ DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
+ break;
+ }
+
+ return pos;
+}
+
+struct komeda_component *
+komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
+{
+ struct komeda_component **pos = NULL;
+ struct komeda_component *c = NULL;
+
+ pos = komeda_pipeline_get_component_pos(pipe, id);
+ if (pos)
+ c = *pos;
+
+ return c;
+}
+
+/** komeda_component_add - Add a component to &komeda_pipeline */
+struct komeda_component *
+komeda_component_add(struct komeda_pipeline *pipe,
+ size_t comp_sz, u32 id, u32 hw_id,
+ struct komeda_component_funcs *funcs,
+ u8 max_active_inputs, u32 supported_inputs,
+ u8 max_active_outputs, u32 __iomem *reg,
+ const char *name_fmt, ...)
+{
+ struct komeda_component **pos;
+ struct komeda_component *c;
+ int idx, *num = NULL;
+
+ if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
+ WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
+ max_active_inputs);
+ return NULL;
+ }
+
+ pos = komeda_pipeline_get_component_pos(pipe, id);
+ if (!pos || (*pos))
+ return NULL;
+
+ if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
+ idx = id - KOMEDA_COMPONENT_LAYER0;
+ num = &pipe->n_layers;
+ if (idx != pipe->n_layers) {
+ DRM_ERROR("please add Layer by id sequence.\n");
+ return NULL;
+ }
+ } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
+ idx = id - KOMEDA_COMPONENT_SCALER0;
+ num = &pipe->n_scalers;
+ if (idx != pipe->n_scalers) {
+ DRM_ERROR("please add Scaler by id sequence.\n");
+ return NULL;
+ }
+ }
+
+ c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
+ if (!c)
+ return NULL;
+
+ c->id = id;
+ c->hw_id = hw_id;
+ c->reg = reg;
+ c->pipeline = pipe;
+ c->max_active_inputs = max_active_inputs;
+ c->max_active_outputs = max_active_outputs;
+ c->supported_inputs = supported_inputs;
+ c->funcs = funcs;
+
+ if (name_fmt) {
+ va_list args;
+
+ va_start(args, name_fmt);
+ vsnprintf(c->name, sizeof(c->name), name_fmt, args);
+ va_end(args);
+ }
+
+ if (num)
+ *num = *num + 1;
+
+ pipe->avail_comps |= BIT(c->id);
+ *pos = c;
+
+ return c;
+}
+
+void komeda_component_destroy(struct komeda_dev *mdev,
+ struct komeda_component *c)
+{
+ devm_kfree(mdev->dev, c);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
new file mode 100644
index 000000000000..8c950bc8ae96
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#ifndef _KOMEDA_PIPELINE_H_
+#define _KOMEDA_PIPELINE_H_
+
+#include <linux/types.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include "malidp_utils.h"
+
+#define KOMEDA_MAX_PIPELINES 2
+#define KOMEDA_PIPELINE_MAX_LAYERS 4
+#define KOMEDA_PIPELINE_MAX_SCALERS 2
+#define KOMEDA_COMPONENT_N_INPUTS 5
+
+/* pipeline component IDs */
+enum {
+ KOMEDA_COMPONENT_LAYER0 = 0,
+ KOMEDA_COMPONENT_LAYER1 = 1,
+ KOMEDA_COMPONENT_LAYER2 = 2,
+ KOMEDA_COMPONENT_LAYER3 = 3,
+ KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
+ KOMEDA_COMPONENT_SCALER0 = 8,
+ KOMEDA_COMPONENT_SCALER1 = 9,
+ KOMEDA_COMPONENT_SPLITTER = 12,
+ KOMEDA_COMPONENT_MERGER = 14,
+ KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
+ KOMEDA_COMPONENT_COMPIZ1 = 17,
+ KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
+ KOMEDA_COMPONENT_IPS1 = 21,
+ KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
+};
+
+#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
+ BIT(KOMEDA_COMPONENT_LAYER1) |\
+ BIT(KOMEDA_COMPONENT_LAYER2) |\
+ BIT(KOMEDA_COMPONENT_LAYER3))
+
+#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
+ BIT(KOMEDA_COMPONENT_SCALER1))
+
+#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
+ BIT(KOMEDA_COMPONENT_COMPIZ1))
+
+#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
+ BIT(KOMEDA_COMPONENT_IPS1))
+struct komeda_component;
+struct komeda_component_state;
+
+/** komeda_component_funcs - component control functions */
+struct komeda_component_funcs {
+ /** @validate: optional,
+ * component may has special requirements or limitations, this function
+ * supply HW the ability to do the further HW specific check.
+ */
+ int (*validate)(struct komeda_component *c,
+ struct komeda_component_state *state);
+ /** @update: update is a active update */
+ void (*update)(struct komeda_component *c,
+ struct komeda_component_state *state);
+ /** @disable: disable component */
+ void (*disable)(struct komeda_component *c);
+ /** @dump_register: Optional, dump registers to seq_file */
+ void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
+};
+
+/**
+ * struct komeda_component
+ *
+ * struct komeda_component describe the data flow capabilities for how to link a
+ * component into the display pipeline.
+ * all specified components are subclass of this structure.
+ */
+struct komeda_component {
+ /** @obj: treat component as private obj */
+ struct drm_private_obj obj;
+ /** @pipeline: the komeda pipeline this component belongs to */
+ struct komeda_pipeline *pipeline;
+ /** @name: component name */
+ char name[32];
+ /**
+ * @reg:
+ * component register base,
+ * which is initialized by chip and used by chip only
+ */
+ u32 __iomem *reg;
+ /** @id: component id */
+ u32 id;
+ /** @hw_ic: component hw id,
+ * which is initialized by chip and used by chip only
+ */
+ u32 hw_id;
+
+ /**
+ * @max_active_inputs:
+ * @max_active_outpus:
+ *
+ * maximum number of inputs/outputs that can be active in the same time
+ * Note:
+ * the number isn't the bit number of @supported_inputs or
+ * @supported_outputs, but may be less than it, since component may not
+ * support enabling all @supported_inputs/outputs at the same time.
+ */
+ u8 max_active_inputs;
+ u8 max_active_outputs;
+ /**
+ * @supported_inputs:
+ * @supported_outputs:
+ *
+ * bitmask of BIT(component->id) for the supported inputs/outputs
+ * describes the possibilities of how a component is linked into a
+ * pipeline.
+ */
+ u32 supported_inputs;
+ u32 supported_outputs;
+
+ /**
+ * @funcs: chip functions to access HW
+ */
+ struct komeda_component_funcs *funcs;
+};
+
+/**
+ * struct komeda_component_output
+ *
+ * a component has multiple outputs, if want to know where the data
+ * comes from, only know the component is not enough, we still need to know
+ * its output port
+ */
+struct komeda_component_output {
+ /** @component: indicate which component the data comes from */
+ struct komeda_component *component;
+ /** @output_port:
+ * the output port of the &komeda_component_output.component
+ */
+ u8 output_port;
+};
+
+/**
+ * struct komeda_component_state
+ *
+ * component_state is the data flow configuration of the component, and it's
+ * the superclass of all specific component_state like @komeda_layer_state,
+ * @komeda_scaler_state
+ */
+struct komeda_component_state {
+ /** @obj: tracking component_state by drm_atomic_state */
+ struct drm_private_state obj;
+ struct komeda_component *component;
+ /**
+ * @binding_user:
+ * currently bound user, the user can be crtc/plane/wb_conn, which is
+ * valid decided by @component and @inputs
+ *
+ * - Layer: its user always is plane.
+ * - compiz/improc/timing_ctrlr: the user is crtc.
+ * - wb_layer: wb_conn;
+ * - scaler: plane when input is layer, wb_conn if input is compiz.
+ */
+ union {
+ struct drm_crtc *crtc;
+ struct drm_plane *plane;
+ struct drm_connector *wb_conn;
+ void *binding_user;
+ };
+ /**
+ * @active_inputs:
+ *
+ * active_inputs is bitmask of @inputs index
+ *
+ * - active_inputs = changed_active_inputs + unchanged_active_inputs
+ * - affected_inputs = old->active_inputs + new->active_inputs;
+ * - disabling_inputs = affected_inputs ^ active_inputs;
+ * - changed_inputs = disabling_inputs + changed_active_inputs;
+ *
+ * NOTE:
+ * changed_inputs doesn't include all active_input but only
+ * @changed_active_inputs, and this bitmask can be used in chip
+ * level for dirty update.
+ */
+ u16 active_inputs;
+ u16 changed_active_inputs;
+ u16 affected_inputs;
+ /**
+ * @inputs:
+ *
+ * the specific inputs[i] only valid on BIT(i) has been set in
+ * @active_inputs, if not the inputs[i] is undefined.
+ */
+ struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
+};
+
+static inline u16 component_disabling_inputs(struct komeda_component_state *st)
+{
+ return st->affected_inputs ^ st->active_inputs;
+}
+
+static inline u16 component_changed_inputs(struct komeda_component_state *st)
+{
+ return component_disabling_inputs(st) | st->changed_active_inputs;
+}
+
+#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
+#define to_cpos(__c) ((struct komeda_component **)&(__c))
+
+/* these structures are going to be filled in in uture patches */
+struct komeda_layer {
+ struct komeda_component base;
+ /* layer specific features and caps */
+ int layer_type; /* RICH, SIMPLE or WB */
+};
+
+struct komeda_layer_state {
+ struct komeda_component_state base;
+ /* layer specific configuration state */
+};
+
+struct komeda_compiz {
+ struct komeda_component base;
+ /* compiz specific features and caps */
+};
+
+struct komeda_compiz_state {
+ struct komeda_component_state base;
+ /* compiz specific configuration state */
+};
+
+struct komeda_scaler {
+ struct komeda_component base;
+ /* scaler features and caps */
+};
+
+struct komeda_scaler_state {
+ struct komeda_component_state base;
+};
+
+struct komeda_improc {
+ struct komeda_component base;
+};
+
+struct komeda_improc_state {
+ struct komeda_component_state base;
+};
+
+/* display timing controller */
+struct komeda_timing_ctrlr {
+ struct komeda_component base;
+};
+
+struct komeda_timing_ctrlr_state {
+ struct komeda_component_state base;
+};
+
+/** struct komeda_pipeline_funcs */
+struct komeda_pipeline_funcs {
+ /* dump_register: Optional, dump registers to seq_file */
+ void (*dump_register)(struct komeda_pipeline *pipe,
+ struct seq_file *sf);
+};
+
+/**
+ * struct komeda_pipeline
+ *
+ * Represent a complete display pipeline and hold all functional components.
+ */
+struct komeda_pipeline {
+ /** @obj: link pipeline as private obj of drm_atomic_state */
+ struct drm_private_obj obj;
+ /** @mdev: the parent komeda_dev */
+ struct komeda_dev *mdev;
+ /** @pxlclk: pixel clock */
+ struct clk *pxlclk;
+ /** @aclk: AXI clock */
+ struct clk *aclk;
+ /** @id: pipeline id */
+ int id;
+ /** @avail_comps: available components mask of pipeline */
+ u32 avail_comps;
+ int n_layers;
+ struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
+ int n_scalers;
+ struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
+ struct komeda_compiz *compiz;
+ struct komeda_layer *wb_layer;
+ struct komeda_improc *improc;
+ struct komeda_timing_ctrlr *ctrlr;
+ struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
+
+ /** @of_node: pipeline dt node */
+ struct device_node *of_node;
+ /** @of_output_port: pipeline output port */
+ struct device_node *of_output_port;
+ /** @of_output_dev: output connector device node */
+ struct device_node *of_output_dev;
+};
+
+/**
+ * struct komeda_pipeline_state
+ *
+ * NOTE:
+ * Unlike the pipeline, pipeline_state doesn’t gather any component_state
+ * into it. It because all component will be managed by drm_atomic_state.
+ */
+struct komeda_pipeline_state {
+ /** @obj: tracking pipeline_state by drm_atomic_state */
+ struct drm_private_state obj;
+ struct komeda_pipeline *pipe;
+ /** @crtc: currently bound crtc */
+ struct drm_crtc *crtc;
+ /**
+ * @active_comps:
+ *
+ * bitmask - BIT(component->id) of active components
+ */
+ u32 active_comps;
+};
+
+#define to_layer(c) container_of(c, struct komeda_layer, base)
+#define to_compiz(c) container_of(c, struct komeda_compiz, base)
+#define to_scaler(c) container_of(c, struct komeda_scaler, base)
+#define to_improc(c) container_of(c, struct komeda_improc, base)
+#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
+
+#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
+#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
+#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
+#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
+#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
+
+#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
+#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
+
+/* pipeline APIs */
+struct komeda_pipeline *
+komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
+ struct komeda_pipeline_funcs *funcs);
+void komeda_pipeline_destroy(struct komeda_dev *mdev,
+ struct komeda_pipeline *pipe);
+
+struct komeda_component *
+komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
+
+/* component APIs */
+struct komeda_component *
+komeda_component_add(struct komeda_pipeline *pipe,
+ size_t comp_sz, u32 id, u32 hw_id,
+ struct komeda_component_funcs *funcs,
+ u8 max_active_inputs, u32 supported_inputs,
+ u8 max_active_outputs, u32 __iomem *reg,
+ const char *name_fmt, ...);
+
+void komeda_component_destroy(struct komeda_dev *mdev,
+ struct komeda_component *c);
+
+#endif /* _KOMEDA_PIPELINE_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
new file mode 100644
index 000000000000..0a4953a9a909
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
+};
+
+static void komeda_plane_destroy(struct drm_plane *plane)
+{
+ drm_plane_cleanup(plane);
+
+ kfree(to_kplane(plane));
+}
+
+static const struct drm_plane_funcs komeda_plane_funcs = {
+};
+
+/* for komeda, which is pipeline can be share between crtcs */
+static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_crtc *crtc;
+ u32 possible_crtcs = 0;
+ int i;
+
+ for (i = 0; i < kms->n_crtcs; i++) {
+ crtc = &kms->crtcs[i];
+
+ if ((pipe == crtc->master) || (pipe == crtc->slave))
+ possible_crtcs |= BIT(i);
+ }
+
+ return possible_crtcs;
+}
+
+/* use Layer0 as primary */
+static u32 get_plane_type(struct komeda_kms_dev *kms,
+ struct komeda_component *c)
+{
+ bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
+
+ return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+}
+
+static int komeda_plane_add(struct komeda_kms_dev *kms,
+ struct komeda_layer *layer)
+{
+ struct komeda_dev *mdev = kms->base.dev_private;
+ struct komeda_component *c = &layer->base;
+ struct komeda_plane *kplane;
+ struct drm_plane *plane;
+ u32 *formats, n_formats = 0;
+ int err;
+
+ kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
+ if (!kplane)
+ return -ENOMEM;
+
+ plane = &kplane->base;
+ kplane->layer = layer;
+
+ formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
+ layer->layer_type, &n_formats);
+
+ err = drm_universal_plane_init(&kms->base, plane,
+ get_possible_crtcs(kms, c->pipeline),
+ &komeda_plane_funcs,
+ formats, n_formats, NULL,
+ get_plane_type(kms, c),
+ "%s", c->name);
+
+ komeda_put_fourcc_list(formats);
+
+ if (err)
+ goto cleanup;
+
+ drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
+
+ return 0;
+cleanup:
+ komeda_plane_destroy(plane);
+ return err;
+}
+
+int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ int i, j, err;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+
+ for (j = 0; j < pipe->n_layers; j++) {
+ err = komeda_plane_add(kms, pipe->layers[j]);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
new file mode 100644
index 000000000000..f1c9e3fefa86
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+static struct drm_private_state *
+komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_pipeline_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ st->active_comps = 0;
+
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
+
+ return &st->obj;
+}
+
+static void
+komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(priv_to_pipe_st(state));
+}
+
+static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
+ .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
+};
+
+static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_pipeline_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->pipe = pipe;
+ drm_atomic_private_obj_init(&kms->base, &pipe->obj, &st->obj,
+ &komeda_pipeline_obj_funcs);
+
+ return 0;
+}
+
+int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ int i, err;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+
+ err = komeda_pipeline_obj_add(kms, pipe);
+ if (err)
+ return err;
+
+ /* Add component */
+ }
+
+ return 0;
+}
+
+void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ struct komeda_component *c;
+ int i, id;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+ dp_for_each_set_bit(id, pipe->avail_comps) {
+ c = komeda_pipeline_get_component(pipe, id);
+
+ drm_atomic_private_obj_fini(&c->obj);
+ }
+ drm_atomic_private_obj_fini(&pipe->obj);
+ }
+}
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index e4d67b70244d..0b2b62f8fa3c 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -13,12 +13,12 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/of_graph.h>
#include <linux/platform_data/simplefb.h>
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index dfad8d06d108..8fc0b884c428 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -22,13 +22,13 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include "hdlcd_drv.h"
#include "hdlcd_regs.h"
@@ -229,7 +229,7 @@ static int hdlcd_debugfs_init(struct drm_minor *minor)
DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver hdlcd_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
+ .driver_features = DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
.irq_handler = hdlcd_irq,
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index e1b72782848c..56aad288666e 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -14,7 +14,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 505f316a192e..ab50ad06e271 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -23,7 +23,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index 91472e5e0c8b..041a64dc7167 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -8,7 +8,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drmP.h>
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 2f7c048c5361..0e91d27921bd 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -9,7 +9,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "armada_crtc.h"
#include "armada_drm.h"
#include "armada_hw.h"
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 20dfb29561c2..ba4a3fab7745 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -12,7 +12,7 @@
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>
#include "armada_crtc.h"
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 7ebd337b60af..08761ff01739 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -8,6 +8,8 @@
#ifndef ARMADA_CRTC_H
#define ARMADA_CRTC_H
+#include <drm/drm_crtc.h>
+
struct armada_gem_object;
struct armada_regs {
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index fa31589b4fc0..e660c5ca52ae 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/of_graph.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_of.h>
#include "armada_crtc.h"
diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c
index 6bd638a54579..058ac7d9920f 100644
--- a/drivers/gpu/drm/armada/armada_fb.c
+++ b/drivers/gpu/drm/armada/armada_fb.c
@@ -5,7 +5,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include "armada_drm.h"
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index bf589c53b908..3871b39d4dea 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -30,6 +30,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "ast_drv.h"
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 373700c05a00..2854399856ba 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -639,13 +639,9 @@ int ast_dumb_create(struct drm_file *file,
static void ast_bo_unref(struct ast_bo **bo)
{
- struct ttm_buffer_object *tbo;
-
if ((*bo) == NULL)
return;
-
- tbo = &((*bo)->bo);
- ttm_bo_unref(&tbo);
+ ttm_bo_put(&((*bo)->bo));
*bo = NULL;
}
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 8bb355d5d43d..97fed0627d1c 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -32,6 +32,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "ast_drv.h"
#include "ast_tables.h"
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 96f4082671fe..8070a558d7b1 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -24,7 +24,7 @@
#include <linux/pinctrl/consumer.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 034a91112098..0be13eceedba 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -720,7 +720,7 @@ static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver atmel_hlcdc_dc_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
+ .driver_features = DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
.irq_handler = atmel_hlcdc_dc_irq_handler,
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 4cc1e03f0aee..70bd540d644e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -31,7 +31,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 9330a076e15a..e836e2de35ce 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -549,7 +549,8 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
- if (!ovl_s->fb ||
+ if (!ovl_s->visible ||
+ !ovl_s->fb ||
ovl_s->fb->format->has_alpha ||
ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
continue;
@@ -601,15 +602,10 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
struct drm_framebuffer *fb = state->base.fb;
const struct drm_display_mode *mode;
struct drm_crtc_state *crtc_state;
- unsigned int patched_crtc_w;
- unsigned int patched_crtc_h;
- unsigned int patched_src_w;
- unsigned int patched_src_h;
unsigned int tmp;
- int x_offset = 0;
- int y_offset = 0;
int hsub = 1;
int vsub = 1;
+ int ret;
int i;
if (!state->base.crtc || !fb)
@@ -618,14 +614,21 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
mode = &crtc_state->adjusted_mode;
- state->src_x = s->src_x;
- state->src_y = s->src_y;
- state->src_h = s->src_h;
- state->src_w = s->src_w;
- state->crtc_x = s->crtc_x;
- state->crtc_y = s->crtc_y;
- state->crtc_h = s->crtc_h;
- state->crtc_w = s->crtc_w;
+ ret = drm_atomic_helper_check_plane_state(s, crtc_state,
+ (1 << 16) / 2048,
+ INT_MAX, true, true);
+ if (ret || !s->visible)
+ return ret;
+
+ state->src_x = s->src.x1;
+ state->src_y = s->src.y1;
+ state->src_w = drm_rect_width(&s->src);
+ state->src_h = drm_rect_height(&s->src);
+ state->crtc_x = s->dst.x1;
+ state->crtc_y = s->dst.y1;
+ state->crtc_w = drm_rect_width(&s->dst);
+ state->crtc_h = drm_rect_height(&s->dst);
+
if ((state->src_x | state->src_y | state->src_w | state->src_h) &
SUBPIXEL_MASK)
return -EINVAL;
@@ -639,45 +642,6 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
return -EINVAL;
- /*
- * Swap width and size in case of 90 or 270 degrees rotation
- */
- if (drm_rotation_90_or_270(state->base.rotation)) {
- tmp = state->crtc_w;
- state->crtc_w = state->crtc_h;
- state->crtc_h = tmp;
- tmp = state->src_w;
- state->src_w = state->src_h;
- state->src_h = tmp;
- }
-
- if (state->crtc_x + state->crtc_w > mode->hdisplay)
- patched_crtc_w = mode->hdisplay - state->crtc_x;
- else
- patched_crtc_w = state->crtc_w;
-
- if (state->crtc_x < 0) {
- patched_crtc_w += state->crtc_x;
- x_offset = -state->crtc_x;
- state->crtc_x = 0;
- }
-
- if (state->crtc_y + state->crtc_h > mode->vdisplay)
- patched_crtc_h = mode->vdisplay - state->crtc_y;
- else
- patched_crtc_h = state->crtc_h;
-
- if (state->crtc_y < 0) {
- patched_crtc_h += state->crtc_y;
- y_offset = -state->crtc_y;
- state->crtc_y = 0;
- }
-
- patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
- state->crtc_w);
- patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
- state->crtc_h);
-
hsub = drm_format_horz_chroma_subsampling(fb->format->format);
vsub = drm_format_vert_chroma_subsampling(fb->format->format);
@@ -692,41 +656,38 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
case DRM_MODE_ROTATE_90:
- offset = ((y_offset + state->src_y + patched_src_w - 1) /
- ydiv) * fb->pitches[i];
- offset += ((x_offset + state->src_x) / xdiv) *
- state->bpp[i];
- state->xstride[i] = ((patched_src_w - 1) / ydiv) *
- fb->pitches[i];
- state->pstride[i] = -fb->pitches[i] - state->bpp[i];
+ offset = (state->src_y / ydiv) *
+ fb->pitches[i];
+ offset += ((state->src_x + state->src_w - 1) /
+ xdiv) * state->bpp[i];
+ state->xstride[i] = -(((state->src_h - 1) / ydiv) *
+ fb->pitches[i]) -
+ (2 * state->bpp[i]);
+ state->pstride[i] = fb->pitches[i] - state->bpp[i];
break;
case DRM_MODE_ROTATE_180:
- offset = ((y_offset + state->src_y + patched_src_h - 1) /
+ offset = ((state->src_y + state->src_h - 1) /
ydiv) * fb->pitches[i];
- offset += ((x_offset + state->src_x + patched_src_w - 1) /
+ offset += ((state->src_x + state->src_w - 1) /
xdiv) * state->bpp[i];
- state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
+ state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
state->bpp[i]) - fb->pitches[i];
state->pstride[i] = -2 * state->bpp[i];
break;
case DRM_MODE_ROTATE_270:
- offset = ((y_offset + state->src_y) / ydiv) *
- fb->pitches[i];
- offset += ((x_offset + state->src_x + patched_src_h - 1) /
- xdiv) * state->bpp[i];
- state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
- fb->pitches[i]) -
- (2 * state->bpp[i]);
- state->pstride[i] = fb->pitches[i] - state->bpp[i];
+ offset = ((state->src_y + state->src_h - 1) /
+ ydiv) * fb->pitches[i];
+ offset += (state->src_x / xdiv) * state->bpp[i];
+ state->xstride[i] = ((state->src_h - 1) / ydiv) *
+ fb->pitches[i];
+ state->pstride[i] = -fb->pitches[i] - state->bpp[i];
break;
case DRM_MODE_ROTATE_0:
default:
- offset = ((y_offset + state->src_y) / ydiv) *
- fb->pitches[i];
- offset += ((x_offset + state->src_x) / xdiv) *
- state->bpp[i];
+ offset = (state->src_y / ydiv) * fb->pitches[i];
+ offset += (state->src_x / xdiv) * state->bpp[i];
state->xstride[i] = fb->pitches[i] -
- ((patched_src_w / xdiv) *
+ ((state->src_w / xdiv) *
state->bpp[i]);
state->pstride[i] = 0;
break;
@@ -735,35 +696,45 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
state->offsets[i] = offset + fb->offsets[i];
}
- state->src_w = patched_src_w;
- state->src_h = patched_src_h;
- state->crtc_w = patched_crtc_w;
- state->crtc_h = patched_crtc_h;
+ /*
+ * Swap width and size in case of 90 or 270 degrees rotation
+ */
+ if (drm_rotation_90_or_270(state->base.rotation)) {
+ tmp = state->src_w;
+ state->src_w = state->src_h;
+ state->src_h = tmp;
+ }
if (!desc->layout.size &&
(mode->hdisplay != state->crtc_w ||
mode->vdisplay != state->crtc_h))
return -EINVAL;
- if (desc->max_height && state->crtc_h > desc->max_height)
- return -EINVAL;
-
- if (desc->max_width && state->crtc_w > desc->max_width)
- return -EINVAL;
-
if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
(!desc->layout.memsize ||
state->base.fb->format->has_alpha))
return -EINVAL;
- if (state->crtc_x < 0 || state->crtc_y < 0)
- return -EINVAL;
+ return 0;
+}
- if (state->crtc_w + state->crtc_x > mode->hdisplay ||
- state->crtc_h + state->crtc_y > mode->vdisplay)
- return -EINVAL;
+static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
+ struct drm_plane_state *old_state)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
- return 0;
+ /* Disable interrupts */
+ atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
+ 0xffffffff);
+
+ /* Disable the layer */
+ atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
+ ATMEL_HLCDC_LAYER_RST |
+ ATMEL_HLCDC_LAYER_A2Q |
+ ATMEL_HLCDC_LAYER_UPDATE);
+
+ /* Clear all pending interrupts */
+ atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
}
static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
@@ -777,6 +748,11 @@ static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
if (!p->state->crtc || !p->state->fb)
return;
+ if (!state->base.visible) {
+ atmel_hlcdc_plane_atomic_disable(p, old_s);
+ return;
+ }
+
atmel_hlcdc_plane_update_pos_and_size(plane, state);
atmel_hlcdc_plane_update_general_settings(plane, state);
atmel_hlcdc_plane_update_format(plane, state);
@@ -798,25 +774,6 @@ static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
}
-static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
- struct drm_plane_state *old_state)
-{
- struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
-
- /* Disable interrupts */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
- 0xffffffff);
-
- /* Disable the layer */
- atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
- ATMEL_HLCDC_LAYER_RST |
- ATMEL_HLCDC_LAYER_A2Q |
- ATMEL_HLCDC_LAYER_UPDATE);
-
- /* Clear all pending interrupts */
- atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
-}
-
static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
{
const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
index cea42ac64d7e..cb55bdc36f3f 100644
--- a/drivers/gpu/drm/bochs/bochs_drv.c
+++ b/drivers/gpu/drm/bochs/bochs_drv.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include "bochs.h"
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index e9d5dbc34676..9cd82e3631fb 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -10,6 +10,7 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
static int defx = 1024;
static int defy = 768;
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index 641a33f134ee..49463348a07a 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -442,5 +442,6 @@ int bochs_gem_prime_mmap(struct drm_gem_object *obj,
{
struct bochs_bo *bo = gem_to_bochs_bo(obj);
- return ttm_fbdev_mmap(vma, &bo->bo);
+ bo->gem.vma_node.vm_node.start = bo->bo.vma_node.vm_node.start;
+ return drm_gem_prime_mmap(obj, vma);
}
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 2fee47b0d50b..8840f396a7b6 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -30,6 +30,7 @@ config DRM_CDNS_DSI
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL_BRIDGE
+ select GENERIC_PHY_MIPI_DPHY
depends on OF
help
Support Cadence DPI to DSI bridge. This is an internal
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 2b6e0832d1cf..996a7e7dbfd6 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -14,8 +14,10 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
#define ADV7511_REG_CHIP_REVISION 0x00
#define ADV7511_REG_N0 0x01
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index d0e98caa2e2a..ec2ca71e1323 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -17,6 +17,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <media/cec.h>
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
index 4cf7bc17ae14..c09aaf93ae1b 100644
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
@@ -31,9 +31,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "analogix-anx78xx.h"
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 4d5b47585834..225f5e5dd69b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -26,8 +26,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/analogix_dp.h>
diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
index ce9496d13986..6166dca6be81 100644
--- a/drivers/gpu/drm/bridge/cdns-dsi.c
+++ b/drivers/gpu/drm/bridge/cdns-dsi.c
@@ -7,12 +7,14 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
#include <linux/clk.h>
+#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
@@ -21,6 +23,9 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
#define IP_CONF 0x0
#define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26)
#define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21)
@@ -419,44 +424,11 @@
#define DSI_NULL_FRAME_OVERHEAD 6
#define DSI_EOT_PKT_SIZE 4
-#define REG_WAKEUP_TIME_NS 800
-#define DPHY_PLL_RATE_HZ 108000000
-
-/* DPHY registers */
-#define DPHY_PMA_CMN(reg) (reg)
-#define DPHY_PMA_LCLK(reg) (0x100 + (reg))
-#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg))
-#define DPHY_PMA_RCLK(reg) (0x600 + (reg))
-#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg))
-#define DPHY_PCS(reg) (0xb00 + (reg))
-
-#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
-#define DPHY_CMN_SSM_EN BIT(0)
-#define DPHY_CMN_TX_MODE_EN BIT(9)
-
-#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40)
-#define DPHY_CMN_PWM_DIV(x) ((x) << 20)
-#define DPHY_CMN_PWM_LOW(x) ((x) << 10)
-#define DPHY_CMN_PWM_HIGH(x) (x)
-
-#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c)
-#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22))
-#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21))
-
-#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50)
-#define DPHY_CMN_IPDIV_FROM_REG BIT(0)
-#define DPHY_CMN_IPDIV(x) ((x) << 1)
-#define DPHY_CMN_OPDIV_FROM_REG BIT(6)
-#define DPHY_CMN_OPDIV(x) ((x) << 7)
-
-#define DPHY_PSM_CFG DPHY_PCS(0x4)
-#define DPHY_PSM_CFG_FROM_REG BIT(0)
-#define DPHY_PSM_CLK_DIV(x) ((x) << 1)
-
struct cdns_dsi_output {
struct mipi_dsi_device *dev;
struct drm_panel *panel;
struct drm_bridge *bridge;
+ union phy_configure_opts phy_opts;
};
enum cdns_dsi_input_id {
@@ -465,14 +437,6 @@ enum cdns_dsi_input_id {
CDNS_DSC_INPUT,
};
-struct cdns_dphy_cfg {
- u8 pll_ipdiv;
- u8 pll_opdiv;
- u16 pll_fbdiv;
- unsigned long lane_bps;
- unsigned int nlanes;
-};
-
struct cdns_dsi_cfg {
unsigned int hfp;
unsigned int hsa;
@@ -481,34 +445,6 @@ struct cdns_dsi_cfg {
unsigned int htotal;
};
-struct cdns_dphy;
-
-enum cdns_dphy_clk_lane_cfg {
- DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0,
- DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1,
- DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2,
- DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3,
-};
-
-struct cdns_dphy_ops {
- int (*probe)(struct cdns_dphy *dphy);
- void (*remove)(struct cdns_dphy *dphy);
- void (*set_psm_div)(struct cdns_dphy *dphy, u8 div);
- void (*set_clk_lane_cfg)(struct cdns_dphy *dphy,
- enum cdns_dphy_clk_lane_cfg cfg);
- void (*set_pll_cfg)(struct cdns_dphy *dphy,
- const struct cdns_dphy_cfg *cfg);
- unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy);
-};
-
-struct cdns_dphy {
- struct cdns_dphy_cfg cfg;
- void __iomem *regs;
- struct clk *psm_clk;
- struct clk *pll_ref_clk;
- const struct cdns_dphy_ops *ops;
-};
-
struct cdns_dsi_input {
enum cdns_dsi_input_id id;
struct drm_bridge bridge;
@@ -526,7 +462,7 @@ struct cdns_dsi {
struct reset_control *dsi_p_rst;
struct clk *dsi_sys_clk;
bool link_initialized;
- struct cdns_dphy *dphy;
+ struct phy *dphy;
};
static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input)
@@ -545,173 +481,13 @@ bridge_to_cdns_dsi_input(struct drm_bridge *bridge)
return container_of(bridge, struct cdns_dsi_input, bridge);
}
-static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy,
- struct cdns_dphy_cfg *cfg,
- unsigned int dpi_htotal,
- unsigned int dpi_bpp,
- unsigned int dpi_hz,
- unsigned int dsi_htotal,
- unsigned int dsi_nlanes,
- unsigned int *dsi_hfp_ext)
-{
- u64 dlane_bps, dlane_bps_max, fbdiv, fbdiv_max, adj_dsi_htotal;
- unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk);
-
- memset(cfg, 0, sizeof(*cfg));
-
- cfg->nlanes = dsi_nlanes;
-
- if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000)
- return -EINVAL;
- else if (pll_ref_hz < 19200000)
- cfg->pll_ipdiv = 1;
- else if (pll_ref_hz < 38400000)
- cfg->pll_ipdiv = 2;
- else if (pll_ref_hz < 76800000)
- cfg->pll_ipdiv = 4;
- else
- cfg->pll_ipdiv = 8;
-
- /*
- * Make sure DSI htotal is aligned on a lane boundary when calculating
- * the expected data rate. This is done by extending HFP in case of
- * misalignment.
- */
- adj_dsi_htotal = dsi_htotal;
- if (dsi_htotal % dsi_nlanes)
- adj_dsi_htotal += dsi_nlanes - (dsi_htotal % dsi_nlanes);
-
- dlane_bps = (u64)dpi_hz * adj_dsi_htotal;
-
- /* data rate in bytes/sec is not an integer, refuse the mode. */
- if (do_div(dlane_bps, dsi_nlanes * dpi_htotal))
- return -EINVAL;
-
- /* data rate was in bytes/sec, convert to bits/sec. */
- dlane_bps *= 8;
-
- if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL)
- return -EINVAL;
- else if (dlane_bps >= 1250000000)
- cfg->pll_opdiv = 1;
- else if (dlane_bps >= 630000000)
- cfg->pll_opdiv = 2;
- else if (dlane_bps >= 320000000)
- cfg->pll_opdiv = 4;
- else if (dlane_bps >= 160000000)
- cfg->pll_opdiv = 8;
-
- /*
- * Allow a deviation of 0.2% on the per-lane data rate to try to
- * recover a potential mismatch between DPI and PPI clks.
- */
- dlane_bps_max = dlane_bps + DIV_ROUND_DOWN_ULL(dlane_bps, 500);
- fbdiv_max = DIV_ROUND_DOWN_ULL(dlane_bps_max * 2 *
- cfg->pll_opdiv * cfg->pll_ipdiv,
- pll_ref_hz);
- fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv *
- cfg->pll_ipdiv,
- pll_ref_hz);
-
- /*
- * Iterate over all acceptable fbdiv and try to find an adjusted DSI
- * htotal length providing an exact match.
- *
- * Note that we could do something even trickier by relying on the fact
- * that a new line is not necessarily aligned on a lane boundary, so,
- * by making adj_dsi_htotal non aligned on a dsi_lanes we can improve a
- * bit the precision. With this, the step would be
- *
- * pll_ref_hz / (2 * opdiv * ipdiv * nlanes)
- *
- * instead of
- *
- * pll_ref_hz / (2 * opdiv * ipdiv)
- *
- * The drawback of this approach is that we would need to make sure the
- * number or lines is a multiple of the realignment periodicity which is
- * a function of the number of lanes and the original misalignment. For
- * example, for NLANES = 4 and HTOTAL % NLANES = 3, it takes 4 lines
- * to realign on a lane:
- * LINE 0: expected number of bytes, starts emitting first byte of
- * LINE 1 on LANE 3
- * LINE 1: expected number of bytes, starts emitting first 2 bytes of
- * LINE 2 on LANES 2 and 3
- * LINE 2: expected number of bytes, starts emitting first 3 bytes of
- * of LINE 3 on LANES 1, 2 and 3
- * LINE 3: one byte less, now things are realigned on LANE 0 for LINE 4
- *
- * I figured this extra complexity was not worth the benefit, but if
- * someone really has unfixable mismatch, that would be something to
- * investigate.
- */
- for (; fbdiv <= fbdiv_max; fbdiv++) {
- u32 rem;
-
- adj_dsi_htotal = (u64)fbdiv * pll_ref_hz * dsi_nlanes *
- dpi_htotal;
-
- /*
- * Do the division in 2 steps to avoid an overflow on the
- * divider.
- */
- rem = do_div(adj_dsi_htotal, dpi_hz);
- if (rem)
- continue;
-
- rem = do_div(adj_dsi_htotal,
- cfg->pll_opdiv * cfg->pll_ipdiv * 2 * 8);
- if (rem)
- continue;
-
- cfg->pll_fbdiv = fbdiv;
- *dsi_hfp_ext = adj_dsi_htotal - dsi_htotal;
- break;
- }
-
- /* No match, let's just reject the display mode. */
- if (!cfg->pll_fbdiv)
- return -EINVAL;
-
- dlane_bps = DIV_ROUND_DOWN_ULL((u64)dpi_hz * adj_dsi_htotal * 8,
- dsi_nlanes * dpi_htotal);
- cfg->lane_bps = dlane_bps;
-
- return 0;
-}
-
-static int cdns_dphy_setup_psm(struct cdns_dphy *dphy)
-{
- unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk);
- unsigned long psm_div;
-
- if (!psm_clk_hz || psm_clk_hz > 100000000)
- return -EINVAL;
-
- psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000);
- if (dphy->ops->set_psm_div)
- dphy->ops->set_psm_div(dphy, psm_div);
-
- return 0;
-}
-
-static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy,
- enum cdns_dphy_clk_lane_cfg cfg)
-{
- if (dphy->ops->set_clk_lane_cfg)
- dphy->ops->set_clk_lane_cfg(dphy, cfg);
-}
-
-static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy,
- const struct cdns_dphy_cfg *cfg)
+static unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode,
+ bool mode_valid_check)
{
- if (dphy->ops->set_pll_cfg)
- dphy->ops->set_pll_cfg(dphy, cfg);
-}
+ if (mode_valid_check)
+ return mode->hsync_start - mode->hdisplay;
-static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)
-{
- return dphy->ops->get_wakeup_time_ns(dphy);
+ return mode->crtc_hsync_start - mode->crtc_hdisplay;
}
static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing,
@@ -731,14 +507,12 @@ static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing,
static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
const struct drm_display_mode *mode,
struct cdns_dsi_cfg *dsi_cfg,
- struct cdns_dphy_cfg *dphy_cfg,
bool mode_valid_check)
{
- unsigned long dsi_htotal = 0, dsi_hss_hsa_hse_hbp = 0;
struct cdns_dsi_output *output = &dsi->output;
- unsigned int dsi_hfp_ext = 0, dpi_hfp, tmp;
+ unsigned int tmp;
bool sync_pulse = false;
- int bpp, nlanes, ret;
+ int bpp, nlanes;
memset(dsi_cfg, 0, sizeof(*dsi_cfg));
@@ -757,8 +531,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
mode->crtc_hsync_end : mode->crtc_hsync_start);
dsi_cfg->hbp = dpi_to_dsi_timing(tmp, bpp, DSI_HBP_FRAME_OVERHEAD);
- dsi_htotal += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD;
- dsi_hss_hsa_hse_hbp += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD;
if (sync_pulse) {
if (mode_valid_check)
@@ -768,49 +540,104 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
dsi_cfg->hsa = dpi_to_dsi_timing(tmp, bpp,
DSI_HSA_FRAME_OVERHEAD);
- dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD;
- dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD;
}
dsi_cfg->hact = dpi_to_dsi_timing(mode_valid_check ?
mode->hdisplay : mode->crtc_hdisplay,
bpp, 0);
- dsi_htotal += dsi_cfg->hact;
+ dsi_cfg->hfp = dpi_to_dsi_timing(mode_to_dpi_hfp(mode, mode_valid_check),
+ bpp, DSI_HFP_FRAME_OVERHEAD);
- if (mode_valid_check)
- dpi_hfp = mode->hsync_start - mode->hdisplay;
- else
- dpi_hfp = mode->crtc_hsync_start - mode->crtc_hdisplay;
+ return 0;
+}
+
+static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi,
+ struct cdns_dsi_cfg *dsi_cfg,
+ struct phy_configure_opts_mipi_dphy *phy_cfg,
+ const struct drm_display_mode *mode,
+ bool mode_valid_check)
+{
+ struct cdns_dsi_output *output = &dsi->output;
+ unsigned long long dlane_bps;
+ unsigned long adj_dsi_htotal;
+ unsigned long dsi_htotal;
+ unsigned long dpi_htotal;
+ unsigned long dpi_hz;
+ unsigned int dsi_hfp_ext;
+ unsigned int lanes = output->dev->lanes;
+
+ dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD;
+ if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD;
- dsi_cfg->hfp = dpi_to_dsi_timing(dpi_hfp, bpp, DSI_HFP_FRAME_OVERHEAD);
+ dsi_htotal += dsi_cfg->hact;
dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD;
- if (mode_valid_check)
- ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg,
- mode->htotal, bpp,
- mode->clock * 1000,
- dsi_htotal, nlanes,
- &dsi_hfp_ext);
- else
- ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg,
- mode->crtc_htotal, bpp,
- mode->crtc_clock * 1000,
- dsi_htotal, nlanes,
- &dsi_hfp_ext);
+ /*
+ * Make sure DSI htotal is aligned on a lane boundary when calculating
+ * the expected data rate. This is done by extending HFP in case of
+ * misalignment.
+ */
+ adj_dsi_htotal = dsi_htotal;
+ if (dsi_htotal % lanes)
+ adj_dsi_htotal += lanes - (dsi_htotal % lanes);
+
+ dpi_hz = (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000;
+ dlane_bps = (unsigned long long)dpi_hz * adj_dsi_htotal;
+
+ /* data rate in bytes/sec is not an integer, refuse the mode. */
+ dpi_htotal = mode_valid_check ? mode->htotal : mode->crtc_htotal;
+ if (do_div(dlane_bps, lanes * dpi_htotal))
+ return -EINVAL;
+
+ /* data rate was in bytes/sec, convert to bits/sec. */
+ phy_cfg->hs_clk_rate = dlane_bps * 8;
+ dsi_hfp_ext = adj_dsi_htotal - dsi_htotal;
+ dsi_cfg->hfp += dsi_hfp_ext;
+ dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext;
+
+ return 0;
+}
+
+static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
+ const struct drm_display_mode *mode,
+ struct cdns_dsi_cfg *dsi_cfg,
+ bool mode_valid_check)
+{
+ struct cdns_dsi_output *output = &dsi->output;
+ struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
+ unsigned long dsi_hss_hsa_hse_hbp;
+ unsigned int nlanes = output->dev->lanes;
+ int ret;
+
+ ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check);
if (ret)
return ret;
- dsi_cfg->hfp += dsi_hfp_ext;
- dsi_htotal += dsi_hfp_ext;
- dsi_cfg->htotal = dsi_htotal;
+ phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000,
+ mipi_dsi_pixel_format_to_bpp(output->dev->format),
+ nlanes, phy_cfg);
+
+ ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check);
+ if (ret)
+ return ret;
+
+ ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &output->phy_opts);
+ if (ret)
+ return ret;
+
+ dsi_hss_hsa_hse_hbp = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD;
+ if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD;
/*
* Make sure DPI(HFP) > DSI(HSS+HSA+HSE+HBP) to guarantee that the FIFO
* is empty before we start a receiving a new line on the DPI
* interface.
*/
- if ((u64)dphy_cfg->lane_bps * dpi_hfp * nlanes <
+ if ((u64)phy_cfg->hs_clk_rate *
+ mode_to_dpi_hfp(mode, mode_valid_check) * nlanes <
(u64)dsi_hss_hsa_hse_hbp *
(mode_valid_check ? mode->clock : mode->crtc_clock) * 1000)
return -EINVAL;
@@ -840,9 +667,8 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
struct cdns_dsi_output *output = &dsi->output;
- struct cdns_dphy_cfg dphy_cfg;
struct cdns_dsi_cfg dsi_cfg;
- int bpp, nlanes, ret;
+ int bpp, ret;
/*
* VFP_DSI should be less than VFP_DPI and VFP_DSI should be at
@@ -860,11 +686,9 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
if ((mode->hdisplay * bpp) % 32)
return MODE_H_ILLEGAL;
- nlanes = output->dev->lanes;
-
- ret = cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, true);
+ ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, true);
if (ret)
- return MODE_CLOCK_RANGE;
+ return MODE_BAD;
return MODE_OK;
}
@@ -885,9 +709,9 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
pm_runtime_put(dsi->base.dev);
}
-static void cdns_dsi_hs_init(struct cdns_dsi *dsi,
- const struct cdns_dphy_cfg *dphy_cfg)
+static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
{
+ struct cdns_dsi_output *output = &dsi->output;
u32 status;
/*
@@ -898,30 +722,10 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi,
DPHY_CMN_PDN | DPHY_PLL_PDN,
dsi->regs + MCTL_DPHY_CFG0);
- /*
- * Configure the internal PSM clk divider so that the DPHY has a
- * 1MHz clk (or something close).
- */
- WARN_ON_ONCE(cdns_dphy_setup_psm(dsi->dphy));
-
- /*
- * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
- * and 8 data lanes, each clk lane can be attache different set of
- * data lanes. The 2 groups are named 'left' and 'right', so here we
- * just say that we want the 'left' clk lane to drive the 'left' data
- * lanes.
- */
- cdns_dphy_set_clk_lane_cfg(dsi->dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT);
-
- /*
- * Configure the DPHY PLL that will be used to generate the TX byte
- * clk.
- */
- cdns_dphy_set_pll_cfg(dsi->dphy, dphy_cfg);
-
- /* Start TX state machine. */
- writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN,
- dsi->dphy->regs + DPHY_CMN_SSM);
+ phy_init(dsi->dphy);
+ phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);
+ phy_configure(dsi->dphy, &output->phy_opts);
+ phy_power_on(dsi->dphy);
/* Activate the PLL and wait until it's locked. */
writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR);
@@ -931,7 +735,7 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi,
status & PLL_LOCKED, 100, 100));
/* De-assert data and clock reset lines. */
writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN |
- DPHY_D_RSTB(dphy_cfg->nlanes) | DPHY_C_RSTB,
+ DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB,
dsi->regs + MCTL_DPHY_CFG0);
}
@@ -977,7 +781,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
struct cdns_dsi *dsi = input_to_dsi(input);
struct cdns_dsi_output *output = &dsi->output;
struct drm_display_mode *mode;
- struct cdns_dphy_cfg dphy_cfg;
+ struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
unsigned long tx_byte_period;
struct cdns_dsi_cfg dsi_cfg;
u32 tmp, reg_wakeup, div;
@@ -990,9 +794,9 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format);
nlanes = output->dev->lanes;
- WARN_ON_ONCE(cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, false));
+ WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false));
- cdns_dsi_hs_init(dsi, &dphy_cfg);
+ cdns_dsi_hs_init(dsi);
cdns_dsi_init_link(dsi);
writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa),
@@ -1028,9 +832,8 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes);
tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8,
- dphy_cfg.lane_bps);
- reg_wakeup = cdns_dphy_get_wakeup_time_ns(dsi->dphy) /
- tx_byte_period;
+ phy_cfg->hs_clk_rate);
+ reg_wakeup = (phy_cfg->hs_prepare + phy_cfg->hs_zero) / tx_byte_period;
writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp),
dsi->regs + VID_DPHY_TIME);
@@ -1344,8 +1147,6 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev)
reset_control_deassert(dsi->dsi_p_rst);
clk_prepare_enable(dsi->dsi_p_clk);
clk_prepare_enable(dsi->dsi_sys_clk);
- clk_prepare_enable(dsi->dphy->psm_clk);
- clk_prepare_enable(dsi->dphy->pll_ref_clk);
return 0;
}
@@ -1354,8 +1155,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
{
struct cdns_dsi *dsi = dev_get_drvdata(dev);
- clk_disable_unprepare(dsi->dphy->pll_ref_clk);
- clk_disable_unprepare(dsi->dphy->psm_clk);
clk_disable_unprepare(dsi->dsi_sys_clk);
clk_disable_unprepare(dsi->dsi_p_clk);
reset_control_assert(dsi->dsi_p_rst);
@@ -1366,121 +1165,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume,
NULL);
-static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy)
-{
- /* Default wakeup time is 800 ns (in a simulated environment). */
- return 800;
-}
-
-static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy,
- const struct cdns_dphy_cfg *cfg)
-{
- u32 fbdiv_low, fbdiv_high;
-
- fbdiv_low = (cfg->pll_fbdiv / 4) - 2;
- fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2;
-
- writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG |
- DPHY_CMN_IPDIV(cfg->pll_ipdiv) |
- DPHY_CMN_OPDIV(cfg->pll_opdiv),
- dphy->regs + DPHY_CMN_OPIPDIV);
- writel(DPHY_CMN_FBDIV_FROM_REG |
- DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high),
- dphy->regs + DPHY_CMN_FBDIV);
- writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) |
- DPHY_CMN_PWM_DIV(0x8),
- dphy->regs + DPHY_CMN_PWM);
-}
-
-static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div)
-{
- writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div),
- dphy->regs + DPHY_PSM_CFG);
-}
-
-/*
- * This is the reference implementation of DPHY hooks. Specific integration of
- * this IP may have to re-implement some of them depending on how they decided
- * to wire things in the SoC.
- */
-static const struct cdns_dphy_ops ref_dphy_ops = {
- .get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns,
- .set_pll_cfg = cdns_dphy_ref_set_pll_cfg,
- .set_psm_div = cdns_dphy_ref_set_psm_div,
-};
-
-static const struct of_device_id cdns_dphy_of_match[] = {
- { .compatible = "cdns,dphy", .data = &ref_dphy_ops },
- { /* sentinel */ },
-};
-
-static struct cdns_dphy *cdns_dphy_probe(struct platform_device *pdev)
-{
- const struct of_device_id *match;
- struct cdns_dphy *dphy;
- struct of_phandle_args args;
- struct resource res;
- int ret;
-
- ret = of_parse_phandle_with_args(pdev->dev.of_node, "phys",
- "#phy-cells", 0, &args);
- if (ret)
- return ERR_PTR(-ENOENT);
-
- match = of_match_node(cdns_dphy_of_match, args.np);
- if (!match || !match->data)
- return ERR_PTR(-EINVAL);
-
- dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
- if (!dphy)
- return ERR_PTR(-ENOMEM);
-
- dphy->ops = match->data;
-
- ret = of_address_to_resource(args.np, 0, &res);
- if (ret)
- return ERR_PTR(ret);
-
- dphy->regs = devm_ioremap_resource(&pdev->dev, &res);
- if (IS_ERR(dphy->regs))
- return ERR_CAST(dphy->regs);
-
- dphy->psm_clk = of_clk_get_by_name(args.np, "psm");
- if (IS_ERR(dphy->psm_clk))
- return ERR_CAST(dphy->psm_clk);
-
- dphy->pll_ref_clk = of_clk_get_by_name(args.np, "pll_ref");
- if (IS_ERR(dphy->pll_ref_clk)) {
- ret = PTR_ERR(dphy->pll_ref_clk);
- goto err_put_psm_clk;
- }
-
- if (dphy->ops->probe) {
- ret = dphy->ops->probe(dphy);
- if (ret)
- goto err_put_pll_ref_clk;
- }
-
- return dphy;
-
-err_put_pll_ref_clk:
- clk_put(dphy->pll_ref_clk);
-
-err_put_psm_clk:
- clk_put(dphy->psm_clk);
-
- return ERR_PTR(ret);
-}
-
-static void cdns_dphy_remove(struct cdns_dphy *dphy)
-{
- if (dphy->ops->remove)
- dphy->ops->remove(dphy);
-
- clk_put(dphy->pll_ref_clk);
- clk_put(dphy->psm_clk);
-}
-
static int cdns_dsi_drm_probe(struct platform_device *pdev)
{
struct cdns_dsi *dsi;
@@ -1519,13 +1203,13 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- dsi->dphy = cdns_dphy_probe(pdev);
+ dsi->dphy = devm_phy_get(&pdev->dev, "dphy");
if (IS_ERR(dsi->dphy))
return PTR_ERR(dsi->dphy);
ret = clk_prepare_enable(dsi->dsi_p_clk);
if (ret)
- goto err_remove_dphy;
+ return ret;
val = readl(dsi->regs + ID_REG);
if (REV_VENDOR_ID(val) != 0xcad) {
@@ -1583,9 +1267,6 @@ err_disable_runtime_pm:
err_disable_pclk:
clk_disable_unprepare(dsi->dsi_p_clk);
-err_remove_dphy:
- cdns_dphy_remove(dsi->dphy);
-
return ret;
}
@@ -1595,7 +1276,6 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev)
mipi_dsi_host_unregister(&dsi->base);
pm_runtime_disable(&pdev->dev);
- cdns_dphy_remove(dsi->dphy);
return 0;
}
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index 9b706789a341..0805801f4e94 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -18,7 +18,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
struct dumb_vga {
struct drm_bridge bridge;
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index 2136c97aeb8e..a01028ec4de6 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -36,8 +36,8 @@
#include <linux/of.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#define EDID_EXT_BLOCK_CNT 0x7E
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index a3e817abace1..fb335afea4cf 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -22,10 +22,10 @@
#include <linux/of_gpio.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#define PTN3460_EDID_ADDR 0x0
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 37baa79e95c3..38eeaf8ba959 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -12,9 +12,9 @@
#include <drm/drm_panel.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_panel.h>
struct panel_bridge {
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index 7334d1b62b71..fda1395b7481 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -26,9 +26,9 @@
#include <linux/regulator/consumer.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
/* Brightness scale on the Parade chip */
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index a5d58f7035c1..08e12fef1349 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -30,8 +30,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#define SII902X_TPI_VIDEO_DATA 0x0
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 129f464cbeb1..a63e5f0dae56 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -25,9 +25,10 @@
#include <drm/drm_of.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/drm_scdc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_hdmi.h>
#include <uapi/linux/media-bus-format.h>
@@ -43,6 +44,11 @@
#define HDMI_EDID_LEN 512
+/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
+#define SCDC_MIN_SOURCE_VERSION 0x1
+
+#define HDMI14_MAX_TMDSCLK 340000000
+
enum hdmi_datamap {
RGB444_8B = 0x01,
RGB444_10B = 0x03,
@@ -93,6 +99,7 @@ struct hdmi_vmode {
unsigned int mpixelclock;
unsigned int mpixelrepetitioninput;
unsigned int mpixelrepetitionoutput;
+ unsigned int mtmdsclock;
};
struct hdmi_data_info {
@@ -537,7 +544,7 @@ static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
mutex_lock(&hdmi->audio_mutex);
- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
hdmi->sample_rate);
mutex_unlock(&hdmi->audio_mutex);
}
@@ -546,7 +553,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
{
mutex_lock(&hdmi->audio_mutex);
hdmi->sample_rate = rate;
- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
hdmi->sample_rate);
mutex_unlock(&hdmi->audio_mutex);
}
@@ -647,6 +654,20 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
}
}
+static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
{
switch (bus_format) {
@@ -876,7 +897,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
u8 val, vp_conf;
if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
- hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) {
+ hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
+ hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
switch (hdmi_bus_fmt_color_depth(
hdmi->hdmi_data.enc_out_bus_format)) {
case 8:
@@ -1015,6 +1037,33 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
}
EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
+/*
+ * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
+ * - The Source shall suspend transmission of the TMDS clock and data
+ * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
+ * from a 0 to a 1 or from a 1 to a 0
+ * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
+ * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
+ * transmission of TMDS clock and data
+ *
+ * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
+ * helper should called right before enabling the TMDS Clock and Data in
+ * the PHY configuration callback.
+ */
+void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
+{
+ unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
+
+ /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
+ if (hdmi->connector.display_info.hdmi.scdc.supported) {
+ if (mtmdsclock > HDMI14_MAX_TMDSCLK)
+ drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
+ else
+ drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
+ }
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
+
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
@@ -1165,6 +1214,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
+ /* TOFIX Will need 420 specific PHY configuration tables */
+
/* PLL/MPLL Cfg - always match on final entry */
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
if (mpixelclock <= mpll_config->mpixelclock)
@@ -1212,10 +1263,13 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+ unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
int ret;
dw_hdmi_phy_power_off(hdmi);
+ dw_hdmi_set_high_tmds_clock_ratio(hdmi);
+
/* Leave low power consumption mode by asserting SVSRET. */
if (phy->has_svsret)
dw_hdmi_phy_enable_svsret(hdmi, 1);
@@ -1237,6 +1291,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
return ret;
}
+ /* Wait for resuming transmission of TMDS clock and data */
+ if (mtmdsclock > HDMI14_MAX_TMDSCLK)
+ msleep(100);
+
return dw_hdmi_phy_power_on(hdmi);
}
@@ -1351,6 +1409,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
frame.colorspace = HDMI_COLORSPACE_YUV444;
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
frame.colorspace = HDMI_COLORSPACE_YUV422;
+ else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
+ frame.colorspace = HDMI_COLORSPACE_YUV420;
else
frame.colorspace = HDMI_COLORSPACE_RGB;
@@ -1504,17 +1564,23 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
- u8 inv_val;
+ u8 inv_val, bytes;
+ struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
- unsigned int vdisplay;
+ unsigned int vdisplay, hdisplay;
- vmode->mpixelclock = mode->clock * 1000;
+ vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
+ vmode->mtmdsclock /= 2;
+
/* Set up HDMI_FC_INVIDCONF */
- inv_val = (hdmi->hdmi_data.hdcp_enable ?
+ inv_val = (hdmi->hdmi_data.hdcp_enable ||
+ vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
+ hdmi_info->scdc.scrambling.low_rates ?
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
@@ -1547,6 +1613,22 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+ hdisplay = mode->hdisplay;
+ hblank = mode->htotal - mode->hdisplay;
+ h_de_hs = mode->hsync_start - mode->hdisplay;
+ hsync_len = mode->hsync_end - mode->hsync_start;
+
+ /*
+ * When we're setting a YCbCr420 mode, we need
+ * to adjust the horizontal timing to suit.
+ */
+ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
+ hdisplay /= 2;
+ hblank /= 2;
+ h_de_hs /= 2;
+ hsync_len /= 2;
+ }
+
vdisplay = mode->vdisplay;
vblank = mode->vtotal - mode->vdisplay;
v_de_vs = mode->vsync_start - mode->vdisplay;
@@ -1563,16 +1645,54 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
vsync_len /= 2;
}
+ /* Scrambling Control */
+ if (hdmi_info->scdc.supported) {
+ if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
+ hdmi_info->scdc.scrambling.low_rates) {
+ /*
+ * HDMI2.0 Specifies the following procedure:
+ * After the Source Device has determined that
+ * SCDC_Present is set (=1), the Source Device should
+ * write the accurate Version of the Source Device
+ * to the Source Version field in the SCDCS.
+ * Source Devices compliant shall set the
+ * Source Version = 1.
+ */
+ drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
+ &bytes);
+ drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION,
+ min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
+
+ /* Enabled Scrambling in the Sink */
+ drm_scdc_set_scrambling(&hdmi->i2c->adap, 1);
+
+ /*
+ * To activate the scrambler feature, you must ensure
+ * that the quasi-static configuration bit
+ * fc_invidconf.HDCP_keepout is set at configuration
+ * time, before the required mc_swrstzreq.tmdsswrst_req
+ * reset request is issued.
+ */
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
+ HDMI_MC_SWRSTZ);
+ hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
+ } else {
+ hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
+ HDMI_MC_SWRSTZ);
+ drm_scdc_set_scrambling(&hdmi->i2c->adap, 0);
+ }
+ }
+
/* Set up horizontal active pixel width */
- hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
- hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+ hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1);
+ hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0);
/* Set up vertical active lines */
hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1);
hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0);
/* Set up horizontal blanking pixel region width */
- hblank = mode->htotal - mode->hdisplay;
hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
@@ -1580,7 +1700,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
/* Set up HSYNC active edge delay width (in pixel clks) */
- h_de_hs = mode->hsync_start - mode->hdisplay;
hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
@@ -1588,7 +1707,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
/* Set up HSYNC active pulse width (in pixel clks) */
- hsync_len = mode->hsync_end - mode->hsync_start;
hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 9d90eb9c46e5..3f3c616eba97 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -255,6 +255,7 @@
#define HDMI_FC_MASK2 0x10DA
#define HDMI_FC_POL2 0x10DB
#define HDMI_FC_PRCONF 0x10E0
+#define HDMI_FC_SCRAMBLER_CTRL 0x10E1
#define HDMI_FC_GMD_STAT 0x1100
#define HDMI_FC_GMD_EN 0x1101
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 23a5977a3b0a..e915ae8c9a92 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -19,9 +19,9 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_mipi_dsi.h>
#include <video/mipi_display.h>
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index afd491018bfc..a20e454ddd64 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -9,11 +9,11 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include <linux/gpio/consumer.h>
#include <linux/of_graph.h>
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 4df07f4cbff5..888980d4bc74 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -34,11 +34,11 @@
#include <linux/slab.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
/* Registers */
@@ -98,6 +98,8 @@
#define DP0_STARTVAL 0x064c
#define DP0_ACTIVEVAL 0x0650
#define DP0_SYNCVAL 0x0654
+#define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15)
+#define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31)
#define DP0_MISC 0x0658
#define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */
#define BPC_6 (0 << 5)
@@ -142,6 +144,8 @@
#define DP0_LTLOOPCTRL 0x06d8
#define DP0_SNKLTCTRL 0x06e4
+#define DP1_SRCCTRL 0x07a0
+
/* PHY */
#define DP_PHY_CTRL 0x0800
#define DP_PHY_RST BIT(28) /* DP PHY Global Soft Reset */
@@ -150,6 +154,7 @@
#define PHY_M1_RST BIT(12) /* Reset PHY1 Main Channel */
#define PHY_RDY BIT(16) /* PHY Main Channels Ready */
#define PHY_M0_RST BIT(8) /* Reset PHY0 Main Channel */
+#define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */
#define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */
#define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */
@@ -540,6 +545,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
unsigned long rate;
u32 value;
int ret;
+ u32 dp_phy_ctrl;
rate = clk_get_rate(tc->refclk);
switch (rate) {
@@ -564,7 +570,10 @@ static int tc_aux_link_setup(struct tc_data *tc)
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
tc_write(SYS_PLLPARAM, value);
- tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN);
+ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN;
+ if (tc->link.base.num_lanes == 2)
+ dp_phy_ctrl |= PHY_2LANE;
+ tc_write(DP_PHY_CTRL, dp_phy_ctrl);
/*
* Initially PLLs are in bypass. Force PLL parameter update,
@@ -720,7 +729,9 @@ static int tc_set_video_mode(struct tc_data *tc,
tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay));
- tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0));
+ tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) |
+ ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) |
+ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0));
tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
@@ -830,12 +841,11 @@ static int tc_main_link_setup(struct tc_data *tc)
if (!tc->mode)
return -EINVAL;
- /* from excel file - DP0_SrcCtrl */
- tc_write(DP0_SRCCTRL, DP0_SRCCTRL_SCRMBLDIS | DP0_SRCCTRL_EN810B |
- DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 |
- DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT);
- /* from excel file - DP1_SrcCtrl */
- tc_write(0x07a0, 0x00003083);
+ tc_write(DP0_SRCCTRL, tc_srcctrl(tc));
+ /* SSCG and BW27 on DP1 must be set to the same as on DP0 */
+ tc_write(DP1_SRCCTRL,
+ (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) |
+ ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0));
rate = clk_get_rate(tc->refclk);
switch (rate) {
@@ -856,8 +866,11 @@ static int tc_main_link_setup(struct tc_data *tc)
}
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
tc_write(SYS_PLLPARAM, value);
+
/* Setup Main Link */
- dp_phy_ctrl = BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN | PHY_M0_EN;
+ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN;
+ if (tc->link.base.num_lanes == 2)
+ dp_phy_ctrl |= PHY_2LANE;
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
msleep(100);
@@ -1106,10 +1119,20 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
+ struct tc_data *tc = connector_to_tc(connector);
+ u32 req, avail;
+ u32 bits_per_pixel = 24;
+
/* DPI interface clock limitation: upto 154 MHz */
if (mode->clock > 154000)
return MODE_CLOCK_HIGH;
+ req = mode->clock * bits_per_pixel / 8;
+ avail = tc->link.base.num_lanes * tc->link.base.rate;
+
+ if (req > avail)
+ return MODE_BAD;
+
return MODE_OK;
}
@@ -1187,7 +1210,8 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
/* Create eDP connector */
drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
- DRM_MODE_CONNECTOR_eDP);
+ tc->panel ? DRM_MODE_CONNECTOR_eDP :
+ DRM_MODE_CONNECTOR_DisplayPort);
if (ret)
return ret;
@@ -1196,6 +1220,10 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
drm_display_info_set_bus_formats(&tc->connector.display_info,
&bus_format, 1);
+ tc->connector.display_info.bus_flags =
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_NEGEDGE |
+ DRM_BUS_FLAG_SYNC_NEGEDGE;
drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder);
return 0;
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 10243965ee7c..f72ee137e5f1 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -6,11 +6,11 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index c3e32138c6bb..7bfb4f338813 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -20,7 +20,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#define HOTPLUG_DEBOUNCE_MS 1100
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index db40b77c7f7c..8ec880f3a322 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -12,6 +12,7 @@
#include <linux/console.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "cirrus_drv.h"
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index ed7dcf212a34..7f9bc32af685 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -17,6 +17,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/cirrus.h>
@@ -359,10 +360,70 @@ static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
};
/* CRTC setup */
+static const uint32_t cirrus_formats_16[] = {
+ DRM_FORMAT_RGB565,
+};
+
+static const uint32_t cirrus_formats_24[] = {
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGB565,
+};
+
+static const uint32_t cirrus_formats_32[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGB565,
+};
+
+static struct drm_plane *cirrus_primary_plane(struct drm_device *dev)
+{
+ const uint32_t *formats;
+ uint32_t nformats;
+ struct drm_plane *primary;
+ int ret;
+
+ switch (cirrus_bpp) {
+ case 16:
+ formats = cirrus_formats_16;
+ nformats = ARRAY_SIZE(cirrus_formats_16);
+ break;
+ case 24:
+ formats = cirrus_formats_24;
+ nformats = ARRAY_SIZE(cirrus_formats_24);
+ break;
+ case 32:
+ formats = cirrus_formats_32;
+ nformats = ARRAY_SIZE(cirrus_formats_32);
+ break;
+ default:
+ return NULL;
+ }
+
+ primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+ if (primary == NULL) {
+ DRM_DEBUG_KMS("Failed to allocate primary plane\n");
+ return NULL;
+ }
+
+ ret = drm_universal_plane_init(dev, primary, 0,
+ &drm_primary_helper_funcs,
+ formats, nformats,
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ kfree(primary);
+ primary = NULL;
+ }
+
+ return primary;
+}
+
static void cirrus_crtc_init(struct drm_device *dev)
{
struct cirrus_device *cdev = dev->dev_private;
struct cirrus_crtc *cirrus_crtc;
+ struct drm_plane *primary;
cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
(CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)),
@@ -371,7 +432,15 @@ static void cirrus_crtc_init(struct drm_device *dev)
if (cirrus_crtc == NULL)
return;
- drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs);
+ primary = cirrus_primary_plane(dev);
+ if (primary == NULL) {
+ kfree(cirrus_crtc);
+ return;
+ }
+
+ drm_crtc_init_with_planes(dev, &cirrus_crtc->base,
+ primary, NULL,
+ &cirrus_crtc_funcs, NULL);
drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
cdev->mode_info.crtc = cirrus_crtc;
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c
index 737f02885c28..40fba1c04dfc 100644
--- a/drivers/gpu/drm/drm_agpsupport.c
+++ b/drivers/gpu/drm/drm_agpsupport.c
@@ -348,7 +348,7 @@ int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
* \return zero on success or a negative number on failure.
*
* Verifies the AGP device is present and has been acquired and looks up the
- * AGP memory entry. If the memory it's currently bound, unbind it via
+ * AGP memory entry. If the memory is currently bound, unbind it via
* unbind_agp(). Frees it via free_agp() as well as the entry itself
* and unlinks from the doubly linked list it's inserted in.
*/
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 54e2ae614dcc..c53ecbd9abdd 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -29,7 +29,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_plane_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_writeback.h>
#include <drm/drm_damage_helper.h>
@@ -331,10 +330,17 @@ update_connector_routing(struct drm_atomic_state *state,
* Since the connector can be unregistered at any point during an
* atomic check or commit, this is racy. But that's OK: all we care
* about is ensuring that userspace can't do anything but shut off the
- * display on a connector that was destroyed after its been notified,
+ * display on a connector that was destroyed after it's been notified,
* not before.
+ *
+ * Additionally, we also want to ignore connector registration when
+ * we're trying to restore an atomic state during system resume since
+ * there's a chance the connector may have been destroyed during the
+ * process, but it's better to ignore that then cause
+ * drm_atomic_helper_resume() to fail.
*/
- if (drm_connector_is_unregistered(connector) && crtc_state->active) {
+ if (!state->duplicated && drm_connector_is_unregistered(connector) &&
+ crtc_state->active) {
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n",
connector->base.id, connector->name);
return -EINVAL;
@@ -686,7 +692,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
/*
* After all the routing has been prepared we need to add in any
- * connector which is itself unchanged, but who's crtc changes it's
+ * connector which is itself unchanged, but whose crtc changes its
* configuration. This must be done before calling mode_fixup in case a
* crtc only changed its mode but has the same set of connectors.
*/
@@ -1671,7 +1677,7 @@ EXPORT_SYMBOL(drm_atomic_helper_async_commit);
* drm_atomic_helper_setup_commit() and related functions.
*
* Committing the actual hardware state is done through the
- * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or it's default
+ * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or its default
* implementation drm_atomic_helper_commit_tail().
*
* RETURNS:
@@ -1894,7 +1900,7 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
* functions. drm_atomic_helper_wait_for_dependencies() must be called before
* actually committing the hardware state, and for nonblocking commits this call
* must be placed in the async worker. See also drm_atomic_helper_swap_state()
- * and it's stall parameter, for when a driver's commit hooks look at the
+ * and its stall parameter, for when a driver's commit hooks look at the
* &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly.
*
* Completion of the hardware commit step must be signalled using
@@ -3181,6 +3187,7 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
return ERR_PTR(-ENOMEM);
state->acquire_ctx = ctx;
+ state->duplicated = true;
drm_for_each_crtc(crtc, dev) {
struct drm_crtc_state *crtc_state;
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c40889888a16..0aabd401d3ca 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -44,8 +44,8 @@
* DOC: overview
*
* This file contains the marshalling and demarshalling glue for the atomic UAPI
- * in all it's form: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
- * SET_PROPERTY IOCTls. Plus interface functions for compatibility helpers and
+ * in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
+ * SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and
* drivers which have special needs to construct their own atomic updates, e.g.
* for load detect or similiar.
*/
@@ -1296,12 +1296,11 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
(arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
return -EINVAL;
- drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
-
state = drm_atomic_state_alloc(dev);
if (!state)
return -ENOMEM;
+ drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
state->acquire_ctx = &ctx;
state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index a39ab2193bfe..e407adb033e7 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -494,7 +494,7 @@ int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data,
* isn't in use.
*
* Searches the map on drm_device::maplist, removes it from the list, see if
- * its being used, and free any associate resource (such as MTRR's) if it's not
+ * it's being used, and free any associated resource (such as MTRR's) if it's not
* being on use.
*
* \sa drm_legacy_addmap
@@ -621,7 +621,7 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
}
}
- /* List has wrapped around to the head pointer, or its empty we didn't
+ /* List has wrapped around to the head pointer, or it's empty we didn't
* find anything.
*/
if (list_empty(&dev->maplist) || !map) {
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 847539645558..dd40eff0911c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1066,7 +1066,7 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
*
* content type (HDMI specific):
* Indicates content type setting to be used in HDMI infoframes to indicate
- * content type for the external device, so that it adjusts it's display
+ * content type for the external device, so that it adjusts its display
* settings accordingly.
*
* The value of this property can be one of the following:
@@ -1367,7 +1367,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
*
* Absence of the property should indicate absence of support.
*
- * "vrr_enabled":
+ * "VRR_ENABLED":
* Default &drm_crtc boolean property that notifies the driver that the
* content on the CRTC is suitable for variable refresh rate presentation.
* The driver will take this property as a hint to enable variable
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index e16aa5ae00b4..ee67c96841fa 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -32,6 +32,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
/**
* DOC: overview
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 54120b6319e7..54a6414c5d96 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -1360,7 +1360,20 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
EXPORT_SYMBOL(drm_dp_read_desc);
/**
- * DRM DP Helpers for DSC
+ * drm_dp_dsc_sink_max_slice_count() - Get the max slice count
+ * supported by the DSC sink.
+ * @dsc_dpcd: DSC capabilities from DPCD
+ * @is_edp: true if its eDP, false for DP
+ *
+ * Read the slice capabilities DPCD register from DSC sink to get
+ * the maximum slice count supported. This is used to populate
+ * the DSC parameters in the &struct drm_dsc_config by the driver.
+ * Driver creates an infoframe using these parameters to populate
+ * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC
+ * infoframe using the helper function drm_dsc_pps_infoframe_pack()
+ *
+ * Returns:
+ * Maximum slice count supported by DSC sink or 0 its invalid
*/
u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
bool is_edp)
@@ -1405,6 +1418,21 @@ u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
}
EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count);
+/**
+ * drm_dp_dsc_sink_line_buf_depth() - Get the line buffer depth in bits
+ * @dsc_dpcd: DSC capabilities from DPCD
+ *
+ * Read the DSC DPCD register to parse the line buffer depth in bits which is
+ * number of bits of precision within the decoder line buffer supported by
+ * the DSC sink. This is used to populate the DSC parameters in the
+ * &struct drm_dsc_config by the driver.
+ * Driver creates an infoframe using these parameters to populate
+ * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC
+ * infoframe using the helper function drm_dsc_pps_infoframe_pack()
+ *
+ * Returns:
+ * Line buffer depth supported by DSC panel or 0 its invalid
+ */
u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
{
u8 line_buf_depth = dsc_dpcd[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT];
@@ -1434,6 +1462,23 @@ u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
}
EXPORT_SYMBOL(drm_dp_dsc_sink_line_buf_depth);
+/**
+ * drm_dp_dsc_sink_supported_input_bpcs() - Get all the input bits per component
+ * values supported by the DSC sink.
+ * @dsc_dpcd: DSC capabilities from DPCD
+ * @dsc_bpc: An array to be filled by this helper with supported
+ * input bpcs.
+ *
+ * Read the DSC DPCD from the sink device to parse the supported bits per
+ * component values. This is used to populate the DSC parameters
+ * in the &struct drm_dsc_config by the driver.
+ * Driver creates an infoframe using these parameters to populate
+ * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC
+ * infoframe using the helper function drm_dsc_pps_infoframe_pack()
+ *
+ * Returns:
+ * Number of input BPC values parsed from the DPCD
+ */
int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
u8 dsc_bpc[3])
{
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 196ebba8af5f..dc7ac0c60547 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -33,7 +33,7 @@
#include <drm/drm_fixed.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
/**
* DOC: dp mst helper
@@ -67,6 +67,64 @@ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux);
static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux);
static void drm_dp_mst_kick_tx(struct drm_dp_mst_topology_mgr *mgr);
+
+#define DP_STR(x) [DP_ ## x] = #x
+
+static const char *drm_dp_mst_req_type_str(u8 req_type)
+{
+ static const char * const req_type_str[] = {
+ DP_STR(GET_MSG_TRANSACTION_VERSION),
+ DP_STR(LINK_ADDRESS),
+ DP_STR(CONNECTION_STATUS_NOTIFY),
+ DP_STR(ENUM_PATH_RESOURCES),
+ DP_STR(ALLOCATE_PAYLOAD),
+ DP_STR(QUERY_PAYLOAD),
+ DP_STR(RESOURCE_STATUS_NOTIFY),
+ DP_STR(CLEAR_PAYLOAD_ID_TABLE),
+ DP_STR(REMOTE_DPCD_READ),
+ DP_STR(REMOTE_DPCD_WRITE),
+ DP_STR(REMOTE_I2C_READ),
+ DP_STR(REMOTE_I2C_WRITE),
+ DP_STR(POWER_UP_PHY),
+ DP_STR(POWER_DOWN_PHY),
+ DP_STR(SINK_EVENT_NOTIFY),
+ DP_STR(QUERY_STREAM_ENC_STATUS),
+ };
+
+ if (req_type >= ARRAY_SIZE(req_type_str) ||
+ !req_type_str[req_type])
+ return "unknown";
+
+ return req_type_str[req_type];
+}
+
+#undef DP_STR
+#define DP_STR(x) [DP_NAK_ ## x] = #x
+
+static const char *drm_dp_mst_nak_reason_str(u8 nak_reason)
+{
+ static const char * const nak_reason_str[] = {
+ DP_STR(WRITE_FAILURE),
+ DP_STR(INVALID_READ),
+ DP_STR(CRC_FAILURE),
+ DP_STR(BAD_PARAM),
+ DP_STR(DEFER),
+ DP_STR(LINK_FAILURE),
+ DP_STR(NO_RESOURCES),
+ DP_STR(DPCD_FAIL),
+ DP_STR(I2C_NAK),
+ DP_STR(ALLOCATE_FAIL),
+ };
+
+ if (nak_reason >= ARRAY_SIZE(nak_reason_str) ||
+ !nak_reason_str[nak_reason])
+ return "unknown";
+
+ return nak_reason_str[nak_reason];
+}
+
+#undef DP_STR
+
/* sideband msg handling */
static u8 drm_dp_msg_header_crc4(const uint8_t *data, size_t num_nibbles)
{
@@ -568,7 +626,7 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
msg->reply_type = (raw->msg[0] & 0x80) >> 7;
msg->req_type = (raw->msg[0] & 0x7f);
- if (msg->reply_type) {
+ if (msg->reply_type == DP_SIDEBAND_REPLY_NAK) {
memcpy(msg->u.nak.guid, &raw->msg[1], 16);
msg->u.nak.reason = raw->msg[17];
msg->u.nak.nak_data = raw->msg[18];
@@ -594,7 +652,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
case DP_POWER_UP_PHY:
return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg);
default:
- DRM_ERROR("Got unknown reply 0x%02x\n", msg->req_type);
+ DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type,
+ drm_dp_mst_req_type_str(msg->req_type));
return false;
}
}
@@ -661,7 +720,8 @@ static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw,
case DP_RESOURCE_STATUS_NOTIFY:
return drm_dp_sideband_parse_resource_status_notify(raw, msg);
default:
- DRM_ERROR("Got unknown request 0x%02x\n", msg->req_type);
+ DRM_ERROR("Got unknown request 0x%02x (%s)\n", msg->req_type,
+ drm_dp_mst_req_type_str(msg->req_type));
return false;
}
}
@@ -881,7 +941,7 @@ static void drm_dp_free_mst_branch_device(struct kref *kref)
* in-memory topology state from being changed in the middle of critical
* operations like changing the internal state of payload allocations. This
* means each branch and port will be considered to be connected to the rest
- * of the topology until it's topology refcount reaches zero. Additionally,
+ * of the topology until its topology refcount reaches zero. Additionally,
* for ports this means that their associated &struct drm_connector will stay
* registered with userspace until the port's refcount reaches 0.
*
@@ -919,8 +979,8 @@ static void drm_dp_free_mst_branch_device(struct kref *kref)
* same way as the C pointers used to reference a structure.
*
* As you can see in the above figure, every branch increments the topology
- * refcount of it's children, and increments the malloc refcount of it's
- * parent. Additionally, every payload increments the malloc refcount of it's
+ * refcount of its children, and increments the malloc refcount of its
+ * parent. Additionally, every payload increments the malloc refcount of its
* assigned port by 1.
*
* So, what would happen if MSTB #3 from the above figure was unplugged from
@@ -937,9 +997,9 @@ static void drm_dp_free_mst_branch_device(struct kref *kref)
* of its parent, and finally its own malloc refcount. For MSTB #4 and port
* #4, this means they both have been disconnected from the topology and freed
* from memory. But, because payload #2 is still holding a reference to port
- * #3, port #3 is removed from the topology but it's &struct drm_dp_mst_port
+ * #3, port #3 is removed from the topology but its &struct drm_dp_mst_port
* is still accessible from memory. This also means port #3 has not yet
- * decremented the malloc refcount of MSTB #3, so it's &struct
+ * decremented the malloc refcount of MSTB #3, so its &struct
* drm_dp_mst_branch will also stay allocated in memory until port #3's
* malloc refcount reaches 0.
*
@@ -1079,7 +1139,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
/**
* drm_dp_mst_topology_try_get_mstb() - Increment the topology refcount of a
- * branch device unless its zero
+ * branch device unless it's zero
* @mstb: &struct drm_dp_mst_branch to increment the topology refcount of
*
* Attempts to grab a topology reference to @mstb, if it hasn't yet been
@@ -1205,7 +1265,7 @@ static void drm_dp_destroy_port(struct kref *kref)
/**
* drm_dp_mst_topology_try_get_port() - Increment the topology refcount of a
- * port unless its zero
+ * port unless it's zero
* @port: &struct drm_dp_mst_port to increment the topology refcount of
*
* Attempts to grab a topology reference to @port, if it hasn't yet been
@@ -1411,7 +1471,7 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
port->mstb->port_parent = port;
/*
* Make sure this port's memory allocation stays
- * around until it's child MSTB releases it
+ * around until its child MSTB releases it
*/
drm_dp_mst_get_port_malloc(port);
@@ -1969,9 +2029,9 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
if (ret > 0) {
int i;
- if (txmsg->reply.reply_type == 1)
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
DRM_DEBUG_KMS("link address nak received\n");
- else {
+ } else {
DRM_DEBUG_KMS("link address reply: %d\n", txmsg->reply.u.link_addr.nports);
for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
DRM_DEBUG_KMS("port %d: input %d, pdt: %d, pn: %d, dpcd_rev: %02x, mcs: %d, ddps: %d, ldps %d, sdp %d/%d\n", i,
@@ -2020,9 +2080,9 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
if (ret > 0) {
- if (txmsg->reply.reply_type == 1)
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
DRM_DEBUG_KMS("enum path resources nak received\n");
- else {
+ } else {
if (port->port_num != txmsg->reply.u.path_resources.port_number)
DRM_ERROR("got incorrect port in response\n");
DRM_DEBUG_KMS("enum path resources %d: %d %d\n", txmsg->reply.u.path_resources.port_number, txmsg->reply.u.path_resources.full_payload_bw_number,
@@ -2132,7 +2192,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
*/
ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
if (ret > 0) {
- if (txmsg->reply.reply_type == 1)
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
ret = -EINVAL;
else
ret = 0;
@@ -2165,7 +2225,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg);
if (ret > 0) {
- if (txmsg->reply.reply_type == 1)
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
ret = -EINVAL;
else
ret = 0;
@@ -2211,7 +2271,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_payload *payload)
{
DRM_DEBUG_KMS("\n");
- /* its okay for these to fail */
+ /* it's okay for these to fail */
if (port) {
drm_dp_payload_send_msg(mgr, port, id, 0);
}
@@ -2423,9 +2483,9 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
if (ret > 0) {
- if (txmsg->reply.reply_type == 1) {
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
ret = -EINVAL;
- } else
+ else
ret = 0;
}
kfree(txmsg);
@@ -2438,7 +2498,7 @@ static int drm_dp_encode_up_ack_reply(struct drm_dp_sideband_msg_tx *msg, u8 req
{
struct drm_dp_sideband_msg_reply_body reply;
- reply.reply_type = 0;
+ reply.reply_type = DP_SIDEBAND_REPLY_ACK;
reply.req_type = req_type;
drm_dp_encode_sideband_reply(&reply, msg);
return 0;
@@ -2745,9 +2805,14 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
}
drm_dp_sideband_parse_reply(&mgr->down_rep_recv, &txmsg->reply);
- if (txmsg->reply.reply_type == 1) {
- DRM_DEBUG_KMS("Got NAK reply: req 0x%02x, reason 0x%02x, nak data 0x%02x\n", txmsg->reply.req_type, txmsg->reply.u.nak.reason, txmsg->reply.u.nak.nak_data);
- }
+
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
+ DRM_DEBUG_KMS("Got NAK reply: req 0x%02x (%s), reason 0x%02x (%s), nak data 0x%02x\n",
+ txmsg->reply.req_type,
+ drm_dp_mst_req_type_str(txmsg->reply.req_type),
+ txmsg->reply.u.nak.reason,
+ drm_dp_mst_nak_reason_str(txmsg->reply.u.nak.reason),
+ txmsg->reply.u.nak.nak_data);
memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
drm_dp_mst_topology_put_mstb(mstb);
@@ -2882,7 +2947,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector
{
enum drm_connector_status status = connector_status_disconnected;
- /* we need to search for the port in the mgr in case its gone */
+ /* we need to search for the port in the mgr in case it's gone */
port = drm_dp_mst_topology_get_port_validated(mgr, port);
if (!port)
return connector_status_disconnected;
@@ -2948,7 +3013,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
{
struct edid *edid = NULL;
- /* we need to search for the port in the mgr in case its gone */
+ /* we need to search for the port in the mgr in case it's gone */
port = drm_dp_mst_topology_get_port_validated(mgr, port);
if (!port)
return NULL;
@@ -3052,10 +3117,6 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
if (IS_ERR(topology_state))
return PTR_ERR(topology_state);
- port = drm_dp_mst_topology_get_port_validated(mgr, port);
- if (port == NULL)
- return -EINVAL;
-
/* Find the current allocation for this port, if any */
list_for_each_entry(pos, &topology_state->vcpis, next) {
if (pos->port == port) {
@@ -3088,10 +3149,8 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
/* Add the new allocation to the state */
if (!vcpi) {
vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL);
- if (!vcpi) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!vcpi)
+ return -ENOMEM;
drm_dp_mst_get_port_malloc(port);
vcpi->port = port;
@@ -3100,8 +3159,6 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
vcpi->vcpi = req_slots;
ret = req_slots;
-out:
- drm_dp_mst_topology_put_port(port);
return ret;
}
EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots);
@@ -3115,7 +3172,7 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots);
* Releases any VCPI slots that have been allocated to a port in the atomic
* state. Any atomic drivers which support MST must call this function in
* their &drm_connector_helper_funcs.atomic_check() callback when the
- * connector will no longer have VCPI allocated (e.g. because it's CRTC was
+ * connector will no longer have VCPI allocated (e.g. because its CRTC was
* removed) when it had VCPI allocated in the previous atomic state.
*
* It is OK to call this even if @port has been removed from the system.
@@ -3203,7 +3260,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n",
pbn, port->vcpi.num_slots);
- /* Keep port allocated until it's payload has been removed */
+ /* Keep port allocated until its payload has been removed */
drm_dp_mst_get_port_malloc(port);
drm_dp_mst_topology_put_port(port);
return true;
@@ -3235,7 +3292,7 @@ EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
{
/*
- * A port with VCPI will remain allocated until it's VCPI is
+ * A port with VCPI will remain allocated until its VCPI is
* released, no verified ref needed
*/
@@ -3246,15 +3303,16 @@ EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots);
/**
* drm_dp_mst_deallocate_vcpi() - deallocate a VCPI
* @mgr: manager for this port
- * @port: unverified port to deallocate vcpi for
+ * @port: port to deallocate vcpi for
+ *
+ * This can be called unconditionally, regardless of whether
+ * drm_dp_mst_allocate_vcpi() succeeded or not.
*/
void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port)
{
- /*
- * A port with VCPI will remain allocated until it's VCPI is
- * released, no verified ref needed
- */
+ if (!port->vcpi.vcpi)
+ return;
drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
port->vcpi.num_slots = 0;
@@ -3893,7 +3951,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs
ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
if (ret > 0) {
- if (txmsg->reply.reply_type == 1) { /* got a NAK back */
+ if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
ret = -EREMOTEIO;
goto out;
}
diff --git a/drivers/gpu/drm/drm_dsc.c b/drivers/gpu/drm/drm_dsc.c
index bc2b23adb072..bce99f95c1a3 100644
--- a/drivers/gpu/drm/drm_dsc.c
+++ b/drivers/gpu/drm/drm_dsc.c
@@ -17,6 +17,12 @@
/**
* DOC: dsc helpers
*
+ * VESA specification for DP 1.4 adds a new feature called Display Stream
+ * Compression (DSC) used to compress the pixel bits before sending it on
+ * DP/eDP/MIPI DSI interface. DSC is required to be enabled so that the existing
+ * display interfaces can support high resolutions at higher frames rates uisng
+ * the maximum available link capacity of these interfaces.
+ *
* These functions contain some common logic and helpers to deal with VESA
* Display Stream Compression standard required for DSC on Display Port/eDP or
* MIPI display interfaces.
@@ -26,6 +32,13 @@
* drm_dsc_dp_pps_header_init() - Initializes the PPS Header
* for DisplayPort as per the DP 1.4 spec.
* @pps_sdp: Secondary data packet for DSC Picture Parameter Set
+ * as defined in &struct drm_dsc_pps_infoframe
+ *
+ * DP 1.4 spec defines the secondary data packet for sending the
+ * picture parameter infoframes from the source to the sink.
+ * This function populates the pps header defined in
+ * &struct drm_dsc_pps_infoframe as per the header bytes defined
+ * in &struct dp_sdp_header.
*/
void drm_dsc_dp_pps_header_init(struct drm_dsc_pps_infoframe *pps_sdp)
{
@@ -38,15 +51,20 @@ EXPORT_SYMBOL(drm_dsc_dp_pps_header_init);
/**
* drm_dsc_pps_infoframe_pack() - Populates the DSC PPS infoframe
- * using the DSC configuration parameters in the order expected
- * by the DSC Display Sink device. For the DSC, the sink device
- * expects the PPS payload in the big endian format for the fields
- * that span more than 1 byte.
*
* @pps_sdp:
- * Secondary data packet for DSC Picture Parameter Set
+ * Secondary data packet for DSC Picture Parameter Set. This is defined
+ * by &struct drm_dsc_pps_infoframe
* @dsc_cfg:
- * DSC Configuration data filled by driver
+ * DSC Configuration data filled by driver as defined by
+ * &struct drm_dsc_config
+ *
+ * DSC source device sends a secondary data packet filled with all the
+ * picture parameter set (PPS) information required by the sink to decode
+ * the compressed frame. Driver populates the dsC PPS infoframe using the DSC
+ * configuration parameters in the order expected by the DSC Display Sink
+ * device. For the DSC, the sink device expects the PPS payload in the big
+ * endian format for the fields that span more than 1 byte.
*/
void drm_dsc_pps_infoframe_pack(struct drm_dsc_pps_infoframe *pps_sdp,
const struct drm_dsc_config *dsc_cfg)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 31fcf94bf825..0e9349ff2d16 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1621,6 +1621,64 @@ static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
var_1->transp.msb_right == var_2->transp.msb_right;
}
+static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
+ u8 depth)
+{
+ switch (depth) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 8; /* 8bit DAC */
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 15:
+ var->red.offset = 10;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ break;
+ case 24:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ default:
+ break;
+ }
+}
+
/**
* drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
* @var: screeninfo to check
@@ -1632,9 +1690,14 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
- if (var->pixclock != 0 || in_dbg_master())
+ if (in_dbg_master())
return -EINVAL;
+ if (var->pixclock != 0) {
+ DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
+ var->pixclock = 0;
+ }
+
if ((drm_format_info_block_width(fb->format, 0) > 1) ||
(drm_format_info_block_height(fb->format, 0) > 1))
return -EINVAL;
@@ -1655,6 +1718,20 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
}
/*
+ * Workaround for SDL 1.2, which is known to be setting all pixel format
+ * fields values to zero in some cases. We treat this situation as a
+ * kind of "use some reasonable autodetected values".
+ */
+ if (!var->red.offset && !var->green.offset &&
+ !var->blue.offset && !var->transp.offset &&
+ !var->red.length && !var->green.length &&
+ !var->blue.length && !var->transp.length &&
+ !var->red.msb_right && !var->green.msb_right &&
+ !var->blue.msb_right && !var->transp.msb_right) {
+ drm_fb_helper_fill_pixel_fmt(var, fb->format->depth);
+ }
+
+ /*
* drm fbdev emulation doesn't support changing the pixel format at all,
* so reject all pixel format changing requests.
*/
@@ -2020,59 +2097,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
info->var.yoffset = 0;
info->var.activate = FB_ACTIVATE_NOW;
- switch (fb->format->depth) {
- case 8:
- info->var.red.offset = 0;
- info->var.green.offset = 0;
- info->var.blue.offset = 0;
- info->var.red.length = 8; /* 8bit DAC */
- info->var.green.length = 8;
- info->var.blue.length = 8;
- info->var.transp.offset = 0;
- info->var.transp.length = 0;
- break;
- case 15:
- info->var.red.offset = 10;
- info->var.green.offset = 5;
- info->var.blue.offset = 0;
- info->var.red.length = 5;
- info->var.green.length = 5;
- info->var.blue.length = 5;
- info->var.transp.offset = 15;
- info->var.transp.length = 1;
- break;
- case 16:
- info->var.red.offset = 11;
- info->var.green.offset = 5;
- info->var.blue.offset = 0;
- info->var.red.length = 5;
- info->var.green.length = 6;
- info->var.blue.length = 5;
- info->var.transp.offset = 0;
- break;
- case 24:
- info->var.red.offset = 16;
- info->var.green.offset = 8;
- info->var.blue.offset = 0;
- info->var.red.length = 8;
- info->var.green.length = 8;
- info->var.blue.length = 8;
- info->var.transp.offset = 0;
- info->var.transp.length = 0;
- break;
- case 32:
- info->var.red.offset = 16;
- info->var.green.offset = 8;
- info->var.blue.offset = 0;
- info->var.red.length = 8;
- info->var.green.length = 8;
- info->var.blue.length = 8;
- info->var.transp.offset = 24;
- info->var.transp.length = 8;
- break;
- default:
- break;
- }
+ drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth);
info->var.xres = fb_width;
info->var.yres = fb_height;
@@ -2483,7 +2508,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
/*
* This function checks if rotation is necessary because of panel orientation
* and if it is, if it is supported.
- * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
+ * If rotation is necessary and supported, it gets set in fb_crtc.rotation.
* If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
* or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
* one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
@@ -3185,9 +3210,7 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client)
static int drm_fbdev_client_restore(struct drm_client_dev *client)
{
- struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
-
- drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
+ drm_fb_helper_lastclose(client->dev);
return 0;
}
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 46f48f245eb5..b1838a41ad43 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -701,7 +701,7 @@ int drm_event_reserve_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_event_reserve_init);
/**
- * drm_event_cancel_free - free a DRM event and release it's space
+ * drm_event_cancel_free - free a DRM event and release its space
* @dev: DRM device
* @p: tracking structure for the pending event
*
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index d90ee03a84c6..ba7e19d4336c 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -238,6 +238,15 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_X0L2, .depth = 0, .num_planes = 1,
.char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
.hsub = 2, .vsub = 2, .is_yuv = true },
+ { .format = DRM_FORMAT_P010, .depth = 0, .num_planes = 2,
+ .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
+ .hsub = 2, .vsub = 2, .is_yuv = true},
+ { .format = DRM_FORMAT_P012, .depth = 0, .num_planes = 2,
+ .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
+ .hsub = 2, .vsub = 2, .is_yuv = true},
+ { .format = DRM_FORMAT_P016, .depth = 0, .num_planes = 2,
+ .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
+ .hsub = 2, .vsub = 2, .is_yuv = true},
};
unsigned int i;
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 7abcb265a108..d8d75e25f6fb 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -773,7 +773,7 @@ EXPORT_SYMBOL(drm_framebuffer_lookup);
* @fb: fb to unregister
*
* Drivers need to call this when cleaning up driver-private framebuffers, e.g.
- * those used for fbdev. Note that the caller must hold a reference of it's own,
+ * those used for fbdev. Note that the caller must hold a reference of its own,
* i.e. the object may not be destroyed through this call (since it'll lead to a
* locking inversion).
*
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 2896ff60552f..d0b9f6a9953f 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -660,7 +660,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
EXPORT_SYMBOL(drm_gem_put_pages);
/**
- * drm_gem_object_lookup - look up a GEM object from it's handle
+ * drm_gem_object_lookup - look up a GEM object from its handle
* @filp: DRM file private date
* @handle: userspace handle
*
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 45a07652fa00..9bd8908d5fd8 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -103,9 +103,6 @@ int drm_irq_install(struct drm_device *dev, int irq)
int ret;
unsigned long sh_flags = 0;
- if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
- return -EOPNOTSUPP;
-
if (irq == 0)
return -EINVAL;
@@ -123,8 +120,8 @@ int drm_irq_install(struct drm_device *dev, int irq)
if (dev->driver->irq_preinstall)
dev->driver->irq_preinstall(dev);
- /* Install handler */
- if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
+ /* PCI devices require shared interrupts. */
+ if (dev->pdev)
sh_flags = IRQF_SHARED;
ret = request_irq(irq, dev->driver->irq_handler,
@@ -174,9 +171,6 @@ int drm_irq_uninstall(struct drm_device *dev)
bool irq_enabled;
int i;
- if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
- return -EOPNOTSUPP;
-
irq_enabled = dev->irq_enabled;
dev->irq_enabled = false;
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index b735704653cb..603b0bd9c5ce 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -528,7 +528,8 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
object_count = cl->object_count;
- object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), object_count * sizeof(__u32));
+ object_ids = memdup_user(u64_to_user_ptr(cl->object_ids),
+ array_size(object_count, sizeof(__u32)));
if (IS_ERR(object_ids))
return PTR_ERR(object_ids);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 3cc5fbd78ee2..2b4f373736c7 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -816,7 +816,7 @@ EXPORT_SYMBOL(drm_mm_scan_add_block);
* When the scan list is empty, the selected memory nodes can be freed. An
* immediately following drm_mm_insert_node_in_range_generic() or one of the
* simpler versions of that function with !DRM_MM_SEARCH_BEST will then return
- * the just freed block (because its at the top of the free_stack list).
+ * the just freed block (because it's at the top of the free_stack list).
*
* Returns:
* True if this block should be evicted, false otherwise. Will always
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index adce9a26bac9..869ac6f4671e 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -751,7 +751,7 @@ int drm_mode_hsync(const struct drm_display_mode *mode)
if (mode->hsync)
return mode->hsync;
- if (mode->htotal < 0)
+ if (mode->htotal <= 0)
return 0;
calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
@@ -1272,7 +1272,7 @@ const char *drm_get_mode_status_name(enum drm_mode_status status)
* @verbose: be verbose about it
*
* This helper function can be used to prune a display mode list after
- * validation has been completed. All modes who's status is not MODE_OK will be
+ * validation has been completed. All modes whose status is not MODE_OK will be
* removed from the list, and if @verbose the status code and mode name is also
* printed to dmesg.
*/
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
index 9150fa385bba..da483125e063 100644
--- a/drivers/gpu/drm/drm_modeset_helper.c
+++ b/drivers/gpu/drm/drm_modeset_helper.c
@@ -21,10 +21,12 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
/**
* DOC: aux kms helpers
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index a9d9df6c85ad..693748ad8b88 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -61,8 +61,9 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
return NULL;
dmah->size = size;
- dmah->vaddr = dma_zalloc_coherent(&dev->pdev->dev, size, &dmah->busaddr,
- GFP_KERNEL | __GFP_COMP);
+ dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size,
+ &dmah->busaddr,
+ GFP_KERNEL | __GFP_COMP);
if (dmah->vaddr == NULL) {
kfree(dmah);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index a1bb157bfdfa..6fd08e04b323 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -36,10 +36,10 @@
#include <drm/drm_client.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
#include "drm_crtc_helper_internal.h"
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
index 79c77c3cad86..f8ec8f9c3e7a 100644
--- a/drivers/gpu/drm/drm_property.c
+++ b/drivers/gpu/drm/drm_property.c
@@ -866,7 +866,7 @@ err:
* value doesn't become invalid part way through the property update due to
* race). The value returned by reference via 'obj' should be passed back
* to drm_property_change_valid_put() after the property is set (and the
- * object to which the property is attached has a chance to take it's own
+ * object to which the property is attached has a chance to take its own
* reference).
*/
bool drm_property_change_valid_get(struct drm_property *property,
diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c
index 8c057829b804..66c41b12719c 100644
--- a/drivers/gpu/drm/drm_rect.c
+++ b/drivers/gpu/drm/drm_rect.c
@@ -208,114 +208,6 @@ int drm_rect_calc_vscale(const struct drm_rect *src,
EXPORT_SYMBOL(drm_rect_calc_vscale);
/**
- * drm_calc_hscale_relaxed - calculate the horizontal scaling factor
- * @src: source window rectangle
- * @dst: destination window rectangle
- * @min_hscale: minimum allowed horizontal scaling factor
- * @max_hscale: maximum allowed horizontal scaling factor
- *
- * Calculate the horizontal scaling factor as
- * (@src width) / (@dst width).
- *
- * If the calculated scaling factor is below @min_vscale,
- * decrease the height of rectangle @dst to compensate.
- *
- * If the calculated scaling factor is above @max_vscale,
- * decrease the height of rectangle @src to compensate.
- *
- * If the scale is below 1 << 16, round down. If the scale is above
- * 1 << 16, round up. This will calculate the scale with the most
- * pessimistic limit calculation.
- *
- * RETURNS:
- * The horizontal scaling factor.
- */
-int drm_rect_calc_hscale_relaxed(struct drm_rect *src,
- struct drm_rect *dst,
- int min_hscale, int max_hscale)
-{
- int src_w = drm_rect_width(src);
- int dst_w = drm_rect_width(dst);
- int hscale = drm_calc_scale(src_w, dst_w);
-
- if (hscale < 0 || dst_w == 0)
- return hscale;
-
- if (hscale < min_hscale) {
- int max_dst_w = src_w / min_hscale;
-
- drm_rect_adjust_size(dst, max_dst_w - dst_w, 0);
-
- return min_hscale;
- }
-
- if (hscale > max_hscale) {
- int max_src_w = dst_w * max_hscale;
-
- drm_rect_adjust_size(src, max_src_w - src_w, 0);
-
- return max_hscale;
- }
-
- return hscale;
-}
-EXPORT_SYMBOL(drm_rect_calc_hscale_relaxed);
-
-/**
- * drm_rect_calc_vscale_relaxed - calculate the vertical scaling factor
- * @src: source window rectangle
- * @dst: destination window rectangle
- * @min_vscale: minimum allowed vertical scaling factor
- * @max_vscale: maximum allowed vertical scaling factor
- *
- * Calculate the vertical scaling factor as
- * (@src height) / (@dst height).
- *
- * If the calculated scaling factor is below @min_vscale,
- * decrease the height of rectangle @dst to compensate.
- *
- * If the calculated scaling factor is above @max_vscale,
- * decrease the height of rectangle @src to compensate.
- *
- * If the scale is below 1 << 16, round down. If the scale is above
- * 1 << 16, round up. This will calculate the scale with the most
- * pessimistic limit calculation.
- *
- * RETURNS:
- * The vertical scaling factor.
- */
-int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
- struct drm_rect *dst,
- int min_vscale, int max_vscale)
-{
- int src_h = drm_rect_height(src);
- int dst_h = drm_rect_height(dst);
- int vscale = drm_calc_scale(src_h, dst_h);
-
- if (vscale < 0 || dst_h == 0)
- return vscale;
-
- if (vscale < min_vscale) {
- int max_dst_h = src_h / min_vscale;
-
- drm_rect_adjust_size(dst, 0, max_dst_h - dst_h);
-
- return min_vscale;
- }
-
- if (vscale > max_vscale) {
- int max_src_h = dst_h * max_vscale;
-
- drm_rect_adjust_size(src, 0, max_src_h - src_h);
-
- return max_vscale;
- }
-
- return vscale;
-}
-EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed);
-
-/**
* drm_rect_debug_print - print the rectangle information
* @prefix: prefix string
* @r: rectangle to print
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 917812448d1b..a32f14cd7398 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -10,8 +10,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/slab.h>
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index cde71ee95a8f..a1b65d26d761 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -48,7 +48,7 @@
* Drivers must initialize the vertical blanking handling core with a call to
* drm_vblank_init(). Minimally, a driver needs to implement
* &drm_crtc_funcs.enable_vblank and &drm_crtc_funcs.disable_vblank plus call
- * drm_crtc_handle_vblank() in it's vblank interrupt handler for working vblank
+ * drm_crtc_handle_vblank() in its vblank interrupt handler for working vblank
* support.
*
* Vertical blanking interrupts can be enabled by the DRM core or by drivers
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 4bf698de5996..a6a7ded37ef1 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -21,7 +21,6 @@
#include <linux/mm_types.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/etnaviv_drm.h>
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index 49a6763693f1..67ae26602024 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -109,16 +109,19 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
}
/* block scheduler */
- kthread_park(gpu->sched.thread);
- drm_sched_hw_job_reset(&gpu->sched, sched_job);
+ drm_sched_stop(&gpu->sched);
+
+ if(sched_job)
+ drm_sched_increase_karma(sched_job);
/* get the GPU back into the init state */
etnaviv_core_dump(gpu);
etnaviv_gpu_recover_hang(gpu);
+ drm_sched_resubmit_jobs(&gpu->sched);
+
/* restart scheduler after GPU is usable again */
- drm_sched_job_recovery(&gpu->sched);
- kthread_unpark(gpu->sched.thread);
+ drm_sched_start(&gpu->sched, true);
}
static void etnaviv_sched_free_job(struct drm_sched_job *sched_job)
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index c8449ae4f4fe..471242a5e580 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -22,10 +22,11 @@
#include <video/videomode.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/analogix_dp.h>
#include <drm/exynos_drm.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 2696289ecc78..96ee83a798c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -13,10 +13,10 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_probe_helper.h>
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 2f0babb67c51..ae425c9a3f7b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -11,9 +11,9 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_panel.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2c75e789b2a7..e1ef9dc9ebf3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -15,8 +15,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index d81e62ae286a..a4253dd55f86 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -13,11 +13,11 @@
#include <asm/unaligned.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
-#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 31eb538a44ae..1f11ab0f8e9d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -13,12 +13,12 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include <uapi/drm/exynos_drm.h>
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index ce9604ca8041..c30dd88cdb25 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -15,7 +15,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/exynos_drm.h>
#include <linux/console.h>
@@ -88,7 +88,6 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
}
fbi->par = helper;
- fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->fbops = &exynos_drm_fb_ops;
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 8d67b2a54be3..05abfed6f7f8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -356,6 +356,11 @@ static int rotator_runtime_resume(struct device *dev)
}
#endif
+static const struct drm_exynos_ipp_limit rotator_s5pv210_rbg888_limits[] = {
+ { IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_16K }, .v = { 8, SZ_16K }) },
+ { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 2) },
+};
+
static const struct drm_exynos_ipp_limit rotator_4210_rbg888_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_16K }, .v = { 8, SZ_16K }) },
{ IPP_SIZE_LIMIT(AREA, .h.align = 4, .v.align = 4) },
@@ -371,6 +376,11 @@ static const struct drm_exynos_ipp_limit rotator_5250_rbg888_limits[] = {
{ IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 2) },
};
+static const struct drm_exynos_ipp_limit rotator_s5pv210_yuv_limits[] = {
+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, SZ_64K }, .v = { 32, SZ_64K }) },
+ { IPP_SIZE_LIMIT(AREA, .h.align = 8, .v.align = 8) },
+};
+
static const struct drm_exynos_ipp_limit rotator_4210_yuv_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, SZ_64K }, .v = { 32, SZ_64K }) },
{ IPP_SIZE_LIMIT(AREA, .h.align = 8, .v.align = 8) },
@@ -381,6 +391,11 @@ static const struct drm_exynos_ipp_limit rotator_4412_yuv_limits[] = {
{ IPP_SIZE_LIMIT(AREA, .h.align = 8, .v.align = 8) },
};
+static const struct exynos_drm_ipp_formats rotator_s5pv210_formats[] = {
+ { IPP_SRCDST_FORMAT(XRGB8888, rotator_s5pv210_rbg888_limits) },
+ { IPP_SRCDST_FORMAT(NV12, rotator_s5pv210_yuv_limits) },
+};
+
static const struct exynos_drm_ipp_formats rotator_4210_formats[] = {
{ IPP_SRCDST_FORMAT(XRGB8888, rotator_4210_rbg888_limits) },
{ IPP_SRCDST_FORMAT(NV12, rotator_4210_yuv_limits) },
@@ -396,6 +411,11 @@ static const struct exynos_drm_ipp_formats rotator_5250_formats[] = {
{ IPP_SRCDST_FORMAT(NV12, rotator_4412_yuv_limits) },
};
+static const struct rot_variant rotator_s5pv210_data = {
+ .formats = rotator_s5pv210_formats,
+ .num_formats = ARRAY_SIZE(rotator_s5pv210_formats),
+};
+
static const struct rot_variant rotator_4210_data = {
.formats = rotator_4210_formats,
.num_formats = ARRAY_SIZE(rotator_4210_formats),
@@ -413,6 +433,9 @@ static const struct rot_variant rotator_5250_data = {
static const struct of_device_id exynos_rotator_match[] = {
{
+ .compatible = "samsung,s5pv210-rotator",
+ .data = &rotator_s5pv210_data,
+ }, {
.compatible = "samsung,exynos4210-rotator",
.data = &rotator_4210_data,
}, {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
index 71270efa64f3..ed1dd1aec902 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2017 Samsung Electronics Co.Ltd
* Author:
- * Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 19697c1362d8..29f4c1932aed 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -19,9 +19,9 @@
#include <drm/exynos_drm.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index b857df67aff0..8e2c02fc66e8 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -15,9 +15,9 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "regs-hdmi.h"
diff --git a/drivers/gpu/drm/exynos/regs-scaler.h b/drivers/gpu/drm/exynos/regs-scaler.h
index fc7ccad75e74..512a2baced11 100644
--- a/drivers/gpu/drm/exynos/regs-scaler.h
+++ b/drivers/gpu/drm/exynos/regs-scaler.h
@@ -2,7 +2,7 @@
*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
*
* Register definition file for Samsung scaler driver
*
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
index 18afc94e4dff..bf256971063d 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
@@ -16,7 +16,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/videomode.h>
#include "fsl_dcu_drm_crtc.h"
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index ceddc3e29258..dfc73aade325 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -24,11 +24,11 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_modeset_helper.h>
+#include <drm/drm_probe_helper.h>
#include "fsl_dcu_drm_crtc.h"
#include "fsl_dcu_drm_drv.h"
@@ -137,7 +137,7 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
static struct drm_driver fsl_dcu_drm_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
+ .driver_features = DRIVER_GEM | DRIVER_MODESET
| DRIVER_PRIME | DRIVER_ATOMIC,
.load = fsl_dcu_load,
.unload = fsl_dcu_unload,
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
index ddc68e476a4d..e447f7d0c304 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
@@ -11,9 +11,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "fsl_dcu_drm_crtc.h"
#include "fsl_dcu_drm_drv.h"
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
index 9554b245746e..2a9e8a82c06a 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
@@ -14,10 +14,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "fsl_dcu_drm_drv.h"
#include "fsl_dcu_drm_plane.h"
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index 2298ed2a9e1c..0a3a62b08240 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -14,9 +14,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "fsl_dcu_drm_drv.h"
#include "fsl_tcon.h"
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index adefae58b5fc..c934b3df1f81 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -405,7 +405,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
strcpy(info->fix.id, "psbdrmfb");
- info->flags = FBINFO_DEFAULT;
if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */
info->fbops = &psbfb_ops;
else if (gtt_roll) { /* GTT rolling seems best */
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index ac32ab5aa002..eefaf4daff2b 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -468,8 +468,7 @@ static const struct file_operations psb_gem_fops = {
};
static struct drm_driver driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \
- DRIVER_MODESET | DRIVER_GEM,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM,
.load = psb_driver_load,
.unload = psb_driver_unload,
.lastclose = drm_fb_helper_lastclose,
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index e05e5399af2d..8280a923b916 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -24,6 +24,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_probe_helper.h>
#include <linux/gpio.h>
#include "gma_display.h"
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index a956545774a3..9316b724e7a2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -18,8 +18,8 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "hibmc_drm_drv.h"
#include "hibmc_drm_regs.h"
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 68c0c297b3a5..8ed94fcd42a7 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -20,7 +20,7 @@
#include <linux/module.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "hibmc_drm_drv.h"
#include "hibmc_drm_regs.h"
@@ -56,8 +56,7 @@ static irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
}
static struct drm_driver hibmc_driver = {
- .driver_features = DRIVER_GEM | DRIVER_MODESET |
- DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.fops = &hibmc_fops,
.name = "hibmc",
.date = "20160828",
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
index edcca1761500..de9d7cc97e44 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -17,8 +17,8 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include "hibmc_drm_drv.h"
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index 744956cea749..d2cf7317930a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -17,7 +17,7 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "hibmc_drm_drv.h"
#include "hibmc_drm_regs.h"
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index b4c7af3ab6ae..3d6c45097f51 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -17,12 +17,17 @@
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
-#include <drm/drm_of.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_encoder_slave.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
#include "dw_dsi_reg.h"
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index bb774202a5a1..73611a92d96c 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -23,13 +23,13 @@
#include <linux/reset.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "kirin_drm_drv.h"
#include "kirin_ade_reg.h"
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 15e32e5d9101..7cb7c042b93f 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -20,13 +20,13 @@
#include <linux/of_graph.h>
#include <drm/drmP.h>
-#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include "kirin_drm_drv.h"
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
index dc6414af5d79..b6e091935977 100644
--- a/drivers/gpu/drm/i2c/ch7006_priv.h
+++ b/drivers/gpu/drm/i2c/ch7006_priv.h
@@ -30,6 +30,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/drm_probe_helper.h>
#include <drm/i2c/ch7006.h>
typedef int64_t fixed;
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
index c52d7a3af786..878ba8d06ce2 100644
--- a/drivers/gpu/drm/i2c/sil164_drv.c
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -27,8 +27,8 @@
#include <linux/module.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/drm_probe_helper.h>
#include <drm/i2c/sil164.h>
struct sil164_priv {
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index ecdb8070ed35..7f34601bb515 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -26,9 +26,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <drm/i2c/tda998x.h>
#include <media/cec-notifier.h>
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 9c106e47e640..bc64b810e0d5 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -2799,6 +2799,7 @@ static int init_broadwell_mmio_info(struct intel_gvt *gvt)
MMIO_DFH(_MMIO(0xe2a0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0xe2b0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0xe2c0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
+ MMIO_DFH(_MMIO(0x21f0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
return 0;
}
diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
index 5e01cc8d9b16..4862fb12778e 100644
--- a/drivers/gpu/drm/i915/gvt/hypercall.h
+++ b/drivers/gpu/drm/i915/gvt/hypercall.h
@@ -47,7 +47,7 @@ struct intel_gvt_mpt {
int (*host_init)(struct device *dev, void *gvt, const void *ops);
void (*host_exit)(struct device *dev);
int (*attach_vgpu)(void *vgpu, unsigned long *handle);
- void (*detach_vgpu)(unsigned long handle);
+ void (*detach_vgpu)(void *vgpu);
int (*inject_msi)(unsigned long handle, u32 addr, u16 data);
unsigned long (*from_virt_to_mfn)(void *p);
int (*enable_page_track)(unsigned long handle, u64 gfn);
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 63eef86a2a85..d5fcc447d22f 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -1147,7 +1147,7 @@ static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
{
unsigned int index;
u64 virtaddr;
- unsigned long req_size, pgoff = 0;
+ unsigned long req_size, pgoff, req_start;
pgprot_t pg_prot;
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
@@ -1165,7 +1165,17 @@ static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
pg_prot = vma->vm_page_prot;
virtaddr = vma->vm_start;
req_size = vma->vm_end - vma->vm_start;
- pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;
+ pgoff = vma->vm_pgoff &
+ ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
+ req_start = pgoff << PAGE_SHIFT;
+
+ if (!intel_vgpu_in_aperture(vgpu, req_start))
+ return -EINVAL;
+ if (req_start + req_size >
+ vgpu_aperture_offset(vgpu) + vgpu_aperture_sz(vgpu))
+ return -EINVAL;
+
+ pgoff = (gvt_aperture_pa_base(vgpu->gvt) >> PAGE_SHIFT) + pgoff;
return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot);
}
@@ -1813,9 +1823,21 @@ static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle)
return 0;
}
-static void kvmgt_detach_vgpu(unsigned long handle)
+static void kvmgt_detach_vgpu(void *p_vgpu)
{
- /* nothing to do here */
+ int i;
+ struct intel_vgpu *vgpu = (struct intel_vgpu *)p_vgpu;
+
+ if (!vgpu->vdev.region)
+ return;
+
+ for (i = 0; i < vgpu->vdev.num_regions; i++)
+ if (vgpu->vdev.region[i].ops->release)
+ vgpu->vdev.region[i].ops->release(vgpu,
+ &vgpu->vdev.region[i]);
+ vgpu->vdev.num_regions = 0;
+ kfree(vgpu->vdev.region);
+ vgpu->vdev.region = NULL;
}
static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
index 5d8b8f228d8f..0f9440128123 100644
--- a/drivers/gpu/drm/i915/gvt/mpt.h
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -99,7 +99,7 @@ static inline void intel_gvt_hypervisor_detach_vgpu(struct intel_vgpu *vgpu)
if (!intel_gvt_host.mpt->detach_vgpu)
return;
- intel_gvt_host.mpt->detach_vgpu(vgpu->handle);
+ intel_gvt_host.mpt->detach_vgpu(vgpu);
}
#define MSI_CAP_CONTROL(offset) (offset + 2)
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index b7957eefb976..1bb8f936fdaa 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -333,6 +333,9 @@ static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
i915_gem_object_put(wa_ctx->indirect_ctx.obj);
+
+ wa_ctx->indirect_ctx.obj = NULL;
+ wa_ctx->indirect_ctx.shadow_va = NULL;
}
static int set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload,
@@ -357,6 +360,33 @@ static int set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload,
return 0;
}
+static int
+intel_gvt_workload_req_alloc(struct intel_vgpu_workload *workload)
+{
+ struct intel_vgpu *vgpu = workload->vgpu;
+ struct intel_vgpu_submission *s = &vgpu->submission;
+ struct i915_gem_context *shadow_ctx = s->shadow_ctx;
+ struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+ struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
+ struct i915_request *rq;
+ int ret = 0;
+
+ lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+ if (workload->req)
+ goto out;
+
+ rq = i915_request_alloc(engine, shadow_ctx);
+ if (IS_ERR(rq)) {
+ gvt_vgpu_err("fail to allocate gem request\n");
+ ret = PTR_ERR(rq);
+ goto out;
+ }
+ workload->req = i915_request_get(rq);
+out:
+ return ret;
+}
+
/**
* intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
* shadow it as well, include ringbuffer,wa_ctx and ctx.
@@ -373,12 +403,11 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
struct intel_context *ce;
- struct i915_request *rq;
int ret;
lockdep_assert_held(&dev_priv->drm.struct_mutex);
- if (workload->req)
+ if (workload->shadow)
return 0;
ret = set_context_ppgtt_from_shadow(workload, shadow_ctx);
@@ -418,22 +447,8 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
goto err_shadow;
}
- rq = i915_request_alloc(engine, shadow_ctx);
- if (IS_ERR(rq)) {
- gvt_vgpu_err("fail to allocate gem request\n");
- ret = PTR_ERR(rq);
- goto err_shadow;
- }
- workload->req = i915_request_get(rq);
-
- ret = populate_shadow_context(workload);
- if (ret)
- goto err_req;
-
+ workload->shadow = true;
return 0;
-err_req:
- rq = fetch_and_zero(&workload->req);
- i915_request_put(rq);
err_shadow:
release_shadow_wa_ctx(&workload->wa_ctx);
err_unpin:
@@ -672,23 +687,31 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
mutex_lock(&vgpu->vgpu_lock);
mutex_lock(&dev_priv->drm.struct_mutex);
+ ret = intel_gvt_workload_req_alloc(workload);
+ if (ret)
+ goto err_req;
+
ret = intel_gvt_scan_and_shadow_workload(workload);
if (ret)
goto out;
- ret = prepare_workload(workload);
+ ret = populate_shadow_context(workload);
+ if (ret) {
+ release_shadow_wa_ctx(&workload->wa_ctx);
+ goto out;
+ }
+ ret = prepare_workload(workload);
out:
- if (ret)
- workload->status = ret;
-
if (!IS_ERR_OR_NULL(workload->req)) {
gvt_dbg_sched("ring id %d submit workload to i915 %p\n",
ring_id, workload->req);
i915_request_add(workload->req);
workload->dispatched = true;
}
-
+err_req:
+ if (ret)
+ workload->status = ret;
mutex_unlock(&dev_priv->drm.struct_mutex);
mutex_unlock(&vgpu->vgpu_lock);
return ret;
@@ -892,11 +915,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
list_del_init(&workload->list);
- if (!workload->status) {
- release_shadow_batch_buffer(workload);
- release_shadow_wa_ctx(&workload->wa_ctx);
- }
-
if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) {
/* if workload->status is not successful means HW GPU
* has occurred GPU hang or something wrong with i915/GVT,
@@ -1262,6 +1280,9 @@ void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload)
{
struct intel_vgpu_submission *s = &workload->vgpu->submission;
+ release_shadow_batch_buffer(workload);
+ release_shadow_wa_ctx(&workload->wa_ctx);
+
if (workload->shadow_mm)
intel_vgpu_mm_put(workload->shadow_mm);
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
index 1e9eec6a32fe..0635b2c4bed7 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.h
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -83,6 +83,7 @@ struct intel_vgpu_workload {
struct i915_request *req;
/* if this workload has been dispatched to i915? */
bool dispatched;
+ bool shadow; /* if workload has done shadow of guest request */
int status;
struct intel_vgpu_mm *shadow_mm;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ca8fa4461fc9..2aeea977283f 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -26,9 +26,10 @@
*
*/
-#include <linux/debugfs.h>
#include <linux/sort.h>
#include <linux/sched/mm.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_fourcc.h>
#include "intel_drv.h"
#include "intel_guc_submission.h"
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 349ba9e23a5b..6630212f2faf 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -41,8 +41,10 @@
#include <linux/vt.h>
#include <acpi/video.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_probe_helper.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
@@ -3018,7 +3020,7 @@ static struct drm_driver driver = {
* deal with them for Intel hardware.
*/
.driver_features =
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |
+ DRIVER_GEM | DRIVER_PRIME |
DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ,
.release = i915_driver_release,
.open = i915_driver_open,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5c1b9d44b7d3..b421bc7a2e26 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -26,6 +26,7 @@
*/
#include <drm/drm_vma_manager.h>
+#include <drm/drm_pci.h>
#include <drm/i915_drm.h>
#include <linux/dma-fence-array.h>
#include <linux/kthread.h>
@@ -36,6 +37,7 @@
#include <linux/swap.h>
#include <linux/pci.h>
#include <linux/dma-buf.h>
+#include <linux/mman.h>
#include "i915_drv.h"
#include "i915_gem_clflush.h"
diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c
index 73c3e8f519e8..c1007245f46d 100644
--- a/drivers/gpu/drm/i915/i915_ioc32.c
+++ b/drivers/gpu/drm/i915/i915_ioc32.c
@@ -29,6 +29,7 @@
#include <linux/compat.h>
#include <drm/i915_drm.h>
+#include <drm/drm_ioctl.h>
#include "i915_drv.h"
struct drm_i915_getparam32 {
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 292e31cb8fb1..92bb32ed27fb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -31,6 +31,8 @@
#include <linux/sysrq.h>
#include <linux/slab.h>
#include <linux/circ_buf.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_drv.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "i915_trace.h"
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index e1529a5a0af4..c4d6b8da9b03 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -26,6 +26,8 @@
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
+#include <drm/drm_drv.h>
+
#include "i915_active.h"
#include "i915_drv.h"
#include "i915_selftest.h"
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index b3b4d78d1dc0..0d9cedb892b0 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -6,6 +6,8 @@
#include <linux/types.h>
#include <linux/tracepoint.h>
+#include <drm/drm_drv.h>
+
#include "i915_drv.h"
#include "intel_drv.h"
#include "intel_ringbuffer.h"
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 16263add3cdd..7cf9290ea34a 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -31,7 +31,9 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+
#include "intel_drv.h"
/**
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 021b94b78862..7961cf0e6951 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -32,7 +32,9 @@
*/
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+
#include "intel_drv.h"
struct intel_plane *intel_plane_alloc(void)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index c2e799a5e63e..3716b2ee362f 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -29,8 +29,8 @@
#include <linux/slab.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
#include "i915_drv.h"
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e53d33edc85d..415d8968f2c5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -24,23 +24,32 @@
* Eric Anholt <eric@anholt.net>
*/
-#include <linux/module.h>
-#include <linux/input.h>
#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/intel-iommu.h>
#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/reservation.h>
#include <linux/slab.h>
#include <linux/vgaarb.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
+
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_dp_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
-#include <drm/drm_atomic_uapi.h>
-#include <linux/intel-iommu.h>
-#include <linux/reservation.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "i915_gem_clflush.h"
+#include "i915_trace.h"
+#include "intel_drv.h"
+#include "intel_dsi.h"
+#include "intel_frontbuffer.h"
#include "intel_drv.h"
#include "intel_dsi.h"
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 8f38d932f2d1..cf709835fb9a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -34,10 +34,10 @@
#include <asm/byteorder.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
+#include <drm/drm_probe_helper.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
#include "i915_drv.h"
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index f90041cb336d..fb67cd931117 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -26,8 +26,8 @@
#include "i915_drv.h"
#include "intel_drv.h"
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -80,17 +80,12 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
pipe_config->pbn = mst_pbn;
- /* Zombie connectors can't have VCPI slots */
- if (!drm_connector_is_unregistered(connector)) {
- slots = drm_dp_atomic_find_vcpi_slots(state,
- &intel_dp->mst_mgr,
- port,
- mst_pbn);
- if (slots < 0) {
- DRM_DEBUG_KMS("failed finding vcpi slots:%d\n",
- slots);
- return slots;
- }
+ slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, port,
+ mst_pbn);
+ if (slots < 0) {
+ DRM_DEBUG_KMS("failed finding vcpi slots:%d\n",
+ slots);
+ return slots;
}
intel_link_compute_m_n(bpp, lane_count,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b4e29b823b04..eec4ed93c335 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -33,12 +33,13 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_dual_mode_helper.h>
#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
+#include <drm/drm_vblank.h>
#include <drm/drm_atomic.h>
#include <media/cec-notifier.h>
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index ec72be4b7a7b..656e684e7c9a 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -38,6 +38,8 @@
* forcibly disable it to allow proper screen updates.
*/
+#include <drm/drm_fourcc.h>
+
#include "intel_drv.h"
#include "i915_drv.h"
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index fc02e6f81309..e8f694b57b8a 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -39,6 +39,8 @@
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+
#include "intel_drv.h"
#include "intel_frontbuffer.h"
#include <drm/i915_drm.h>
diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c
index 5d5336fbe7b0..f8239bca3820 100644
--- a/drivers/gpu/drm/i915/intel_lpe_audio.c
+++ b/drivers/gpu/drm/i915/intel_lpe_audio.c
@@ -65,6 +65,7 @@
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
#include "i915_drv.h"
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index fc2e283d326b..c0df1dbb0069 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -26,6 +26,8 @@
* Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
*/
#include <drm/i915_drm.h>
+#include <drm/drm_fourcc.h>
+
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_drv.h"
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index c7ec9b169046..4c0e43caa5cd 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -26,13 +26,16 @@
*/
#include <linux/cpufreq.h>
+#include <linux/module.h>
#include <linux/pm_runtime.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+
#include "i915_drv.h"
#include "intel_drv.h"
#include "../../../platform/x86/intel_ips.h"
-#include <linux/module.h>
-#include <drm/drm_atomic_helper.h>
/**
* DOC: RC6
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index 77a26fd3a44a..06393cd1067d 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -13,7 +13,7 @@
#include <linux/regmap.h>
#include <drm/drm_of.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 820c7e3878f0..44da0f5d0ed9 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -12,13 +12,13 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 2c5bbe317353..383733302280 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -12,9 +12,9 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.h>
@@ -643,8 +643,10 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
int bus_format;
ret = of_property_read_u32(child, "reg", &i);
- if (ret || i < 0 || i > 1)
- return -EINVAL;
+ if (ret || i < 0 || i > 1) {
+ ret = -EINVAL;
+ goto free_child;
+ }
if (!of_device_is_available(child))
continue;
@@ -657,7 +659,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
channel = &imx_ldb->channel[i];
channel->ldb = imx_ldb;
channel->chno = i;
- channel->child = child;
/*
* The output port is port@4 with an external 4-port mux or
@@ -667,13 +668,13 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
imx_ldb->lvds_mux ? 4 : 2, 0,
&channel->panel, &channel->bridge);
if (ret && ret != -ENODEV)
- return ret;
+ goto free_child;
/* panel ddc only if there is no bridge */
if (!channel->bridge) {
ret = imx_ldb_panel_ddc(dev, channel, child);
if (ret)
- return ret;
+ goto free_child;
}
bus_format = of_get_bus_format(dev, child);
@@ -689,18 +690,26 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
if (bus_format < 0) {
dev_err(dev, "could not determine data mapping: %d\n",
bus_format);
- return bus_format;
+ ret = bus_format;
+ goto free_child;
}
channel->bus_format = bus_format;
+ channel->child = child;
ret = imx_ldb_register(drm, channel);
- if (ret)
- return ret;
+ if (ret) {
+ channel->child = NULL;
+ goto free_child;
+ }
}
dev_set_drvdata(dev, imx_ldb);
return 0;
+
+free_child:
+ of_node_put(child);
+ return ret;
}
static void imx_ldb_unbind(struct device *dev, struct device *master,
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index 293dd5752583..e725af8a0025 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -17,7 +17,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 058b53c0aa7e..3c62167a9251 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -4,19 +4,19 @@
*
* Copyright (C) 2011 Sascha Hauer, Pengutronix
*/
+#include <linux/clk.h>
#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/export.h>
#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <linux/clk.h>
-#include <linux/errno.h>
-#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index c390924de93d..21e964f6ab5c 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -370,9 +370,9 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
if (ret)
return ret;
- /* CRTC should be enabled */
+ /* nothing to check when disabling or disabled */
if (!crtc_state->enable)
- return -EINVAL;
+ return 0;
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index f3ce51121dd6..1a76de1e8e7b 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -10,9 +10,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/videodev2.h>
#include <video/of_display_timing.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 62a9d47df948..22e68a100e7b 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -13,7 +13,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_of.h>
#include <linux/kernel.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 92ecb9bf982c..acad088173da 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -14,8 +14,8 @@
#include <asm/barrier.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <soc/mediatek/smi.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 6422e99952fe..cf59ea9bccfd 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -15,10 +15,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
#include <linux/iommu.h>
#include <linux/of_address.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c
index be5f6f1daf55..e20fcaef2851 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c
@@ -12,7 +12,7 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 27b507eb4a99..b00eb2d2e086 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -13,10 +13,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/iopoll.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 12ad00d01063..915cc84621ae 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -14,7 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_edid.h>
#include <linux/arm-smccc.h>
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index 75d97f1b2e8f..43e29984f8b1 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -30,7 +30,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_flip_work.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "meson_crtc.h"
#include "meson_plane.h"
@@ -46,7 +46,6 @@ struct meson_crtc {
struct drm_crtc base;
struct drm_pending_vblank_event *event;
struct meson_drm *priv;
- bool enabled;
};
#define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
@@ -82,7 +81,8 @@ static const struct drm_crtc_funcs meson_crtc_funcs = {
};
-static void meson_crtc_enable(struct drm_crtc *crtc)
+static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
struct drm_crtc_state *crtc_state = crtc->state;
@@ -108,20 +108,6 @@ static void meson_crtc_enable(struct drm_crtc *crtc)
drm_crtc_vblank_on(crtc);
- meson_crtc->enabled = true;
-}
-
-static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
-{
- struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
- struct meson_drm *priv = meson_crtc->priv;
-
- DRM_DEBUG_DRIVER("\n");
-
- if (!meson_crtc->enabled)
- meson_crtc_enable(crtc);
-
priv->viu.osd1_enabled = true;
}
@@ -153,8 +139,6 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
crtc->state->event = NULL;
}
-
- meson_crtc->enabled = false;
}
static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
@@ -163,9 +147,6 @@ static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
unsigned long flags;
- if (crtc->state->enable && !meson_crtc->enabled)
- meson_crtc_enable(crtc);
-
if (crtc->state->event) {
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 1e360828ac38..2281ed3eb774 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -30,14 +30,14 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_flip_work.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
-#include <drm/drm_fb_helper.h>
#include "meson_drv.h"
#include "meson_plane.h"
@@ -75,6 +75,10 @@ static const struct drm_mode_config_funcs meson_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
};
+static const struct drm_mode_config_helper_funcs meson_mode_config_helpers = {
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
static irqreturn_t meson_irq(int irq, void *arg)
{
struct drm_device *dev = arg;
@@ -90,7 +94,7 @@ static irqreturn_t meson_irq(int irq, void *arg)
DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver meson_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
+ .driver_features = DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
@@ -286,6 +290,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
drm->mode_config.max_width = 3840;
drm->mode_config.max_height = 2160;
drm->mode_config.funcs = &meson_mode_config_funcs;
+ drm->mode_config.helper_private = &meson_mode_config_helpers;
/* Hardware Initialization */
@@ -408,8 +413,10 @@ static int meson_probe_remote(struct platform_device *pdev,
remote_node = of_graph_get_remote_port_parent(ep);
if (!remote_node ||
remote_node == parent || /* Ignore parent endpoint */
- !of_device_is_available(remote_node))
+ !of_device_is_available(remote_node)) {
+ of_node_put(remote_node);
continue;
+ }
count += meson_probe_remote(pdev, match, remote, remote_node);
@@ -428,10 +435,13 @@ static int meson_drv_probe(struct platform_device *pdev)
for_each_endpoint_of_node(np, ep) {
remote = of_graph_get_remote_port_parent(ep);
- if (!remote || !of_device_is_available(remote))
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
continue;
+ }
count += meson_probe_remote(pdev, &match, np, remote);
+ of_node_put(remote);
}
if (count && !match)
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index bc25001b8207..e28814f4ea6c 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -26,9 +26,9 @@
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_hdmi.h>
#include <uapi/linux/media-bus-format.h>
@@ -365,7 +365,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
unsigned int wr_clk =
readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
- DRM_DEBUG_DRIVER("\"%s\"\n", mode->name);
+ DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name,
+ mode->clock > 340000 ? 40 : 10);
/* Enable clocks */
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
@@ -385,9 +386,17 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
/* Enable normal output to PHY */
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
- /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
+ /* TMDS pattern setup (TOFIX Handle the YUV420 case) */
+ if (mode->clock > 340000) {
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
+ 0x03ff03ff);
+ } else {
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
+ 0x001f001f);
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
+ 0x001f001f);
+ }
/* Load TMDS pattern */
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
@@ -413,6 +422,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
/* Disable clock, fifo, fifo_wr */
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
+ dw_hdmi_set_high_tmds_clock_ratio(hdmi);
+
msleep(100);
/* Reset PHY 3 times in a row */
@@ -557,6 +568,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
+ /* If sink max TMDS clock, we reject the mode */
+ if (mode->clock > connector->display_info.max_tmds_clock)
+ return MODE_BAD;
+
/* Check against non-VIC supported modes */
if (!vic) {
status = meson_venc_hdmi_supported_mode(mode);
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 0ba04f6813e6..66d73a932d19 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -848,6 +848,8 @@ struct meson_hdmi_venc_vic_mode {
{ 93, &meson_hdmi_encp_mode_2160p24 },
{ 94, &meson_hdmi_encp_mode_2160p25 },
{ 95, &meson_hdmi_encp_mode_2160p30 },
+ { 96, &meson_hdmi_encp_mode_2160p25 },
+ { 97, &meson_hdmi_encp_mode_2160p30 },
{ 0, NULL}, /* sentinel */
};
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index f7945bae3b4a..d622d817b6df 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -26,9 +26,9 @@
#include <linux/of_graph.h>
#include <drm/drmP.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "meson_venc_cvbs.h"
#include "meson_venc.h"
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index 1aad27813c23..6e1d1054ad06 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -57,7 +57,7 @@ static const struct file_operations mga_driver_fops = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_LEGACY |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ,
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load,
.unload = mga_driver_unload,
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 79d54103d470..163255099779 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -33,7 +33,7 @@ int mgag200_framebuffer_init(struct drm_device *dev,
struct drm_gem_object *obj)
{
int ret;
-
+
drm_helper_mode_fill_fb_struct(dev, &gfb->base, mode_cmd);
gfb->obj = obj;
ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
@@ -318,13 +318,9 @@ int mgag200_dumb_create(struct drm_file *file,
static void mgag200_bo_unref(struct mgag200_bo **bo)
{
- struct ttm_buffer_object *tbo;
-
if ((*bo) == NULL)
return;
-
- tbo = &((*bo)->bo);
- ttm_bo_unref(&tbo);
+ ttm_bo_put(&((*bo)->bo));
*bo = NULL;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index acf7bfe68454..7481a3d556ad 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -16,6 +16,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 5beb83d1cf87..ce1b3cc4bf6d 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -944,7 +944,7 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq)
np = dev_pm_opp_get_of_node(opp);
if (np) {
- of_property_read_u32(np, "qcom,level", &val);
+ of_property_read_u32(np, "opp-level", &val);
of_node_put(np);
}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 2e4372ef17a3..2cfee1a4fe0b 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -765,7 +765,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
adreno_gpu->rev = config->rev;
adreno_gpu_config.ioname = "kgsl_3d0_reg_memory";
- adreno_gpu_config.irqname = "kgsl_3d0_irq";
adreno_gpu_config.va_start = SZ_16M;
adreno_gpu_config.va_end = 0xffffffff;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 9be7c355debd..b776fca571f3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -20,10 +20,10 @@
#include <linux/sort.h>
#include <linux/debugfs.h>
#include <linux/ktime.h>
-#include <drm/drm_mode.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
#include "dpu_kms.h"
@@ -465,8 +465,6 @@ static void _dpu_crtc_setup_mixer_for_encoder(
return;
}
- mixer->encoder = enc;
-
cstate->num_mixers++;
DPU_DEBUG("setup mixer %d: lm %d\n",
i, mixer->hw_lm->idx - LM_0);
@@ -718,11 +716,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async)
* may delay and flush at an irq event (e.g. ppdone)
*/
drm_for_each_encoder_mask(encoder, crtc->dev,
- crtc->state->encoder_mask) {
- struct dpu_encoder_kickoff_params params = { 0 };
- dpu_encoder_prepare_for_kickoff(encoder, &params, async);
- }
-
+ crtc->state->encoder_mask)
+ dpu_encoder_prepare_for_kickoff(encoder, async);
if (!async) {
/* wait for frame_event_done completion */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
index dbfb38a1986c..e59d62be4980 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
@@ -84,14 +84,12 @@ struct dpu_crtc_smmu_state_data {
* struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC
* @hw_lm: LM HW Driver context
* @lm_ctl: CTL Path HW driver context
- * @encoder: Encoder attached to this lm & ctl
* @mixer_op_mode: mixer blending operation mode
* @flush_mask: mixer flush mask for ctl, mixer and pipe
*/
struct dpu_crtc_mixer {
struct dpu_hw_mixer *hw_lm;
struct dpu_hw_ctl *lm_ctl;
- struct drm_encoder *encoder;
u32 mixer_op_mode;
u32 flush_mask;
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 36158b7d99cd..5aa3307f3f0c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -24,7 +24,7 @@
#include "msm_drv.h"
#include "dpu_kms.h"
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "dpu_hwio.h"
#include "dpu_hw_catalog.h"
#include "dpu_hw_intf.h"
@@ -205,7 +205,7 @@ struct dpu_encoder_virt {
bool idle_pc_supported;
struct mutex rc_lock;
enum dpu_enc_rc_states rc_state;
- struct kthread_delayed_work delayed_off_work;
+ struct delayed_work delayed_off_work;
struct kthread_work vsync_event_work;
struct msm_display_topology topology;
bool mode_set_complete;
@@ -742,7 +742,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
{
struct dpu_encoder_virt *dpu_enc;
struct msm_drm_private *priv;
- struct msm_drm_thread *disp_thread;
bool is_vid_mode = false;
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
@@ -755,12 +754,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
is_vid_mode = dpu_enc->disp_info.capabilities &
MSM_DISPLAY_CAP_VID_MODE;
- if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
- DPU_ERROR("invalid crtc index\n");
- return -EINVAL;
- }
- disp_thread = &priv->disp_thread[drm_enc->crtc->index];
-
/*
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
* events and return early for other events (ie wb display).
@@ -777,8 +770,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
switch (sw_event) {
case DPU_ENC_RC_EVENT_KICKOFF:
/* cancel delayed off work, if any */
- if (kthread_cancel_delayed_work_sync(
- &dpu_enc->delayed_off_work))
+ if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work))
DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n",
sw_event);
@@ -837,10 +829,8 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
return 0;
}
- kthread_queue_delayed_work(
- &disp_thread->worker,
- &dpu_enc->delayed_off_work,
- msecs_to_jiffies(dpu_enc->idle_timeout));
+ queue_delayed_work(priv->wq, &dpu_enc->delayed_off_work,
+ msecs_to_jiffies(dpu_enc->idle_timeout));
trace_dpu_enc_rc(DRMID(drm_enc), sw_event,
dpu_enc->idle_pc_supported, dpu_enc->rc_state,
@@ -849,8 +839,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
case DPU_ENC_RC_EVENT_PRE_STOP:
/* cancel delayed off work, if any */
- if (kthread_cancel_delayed_work_sync(
- &dpu_enc->delayed_off_work))
+ if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work))
DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n",
sw_event);
@@ -1368,7 +1357,7 @@ static void dpu_encoder_frame_done_callback(
}
}
-static void dpu_encoder_off_work(struct kthread_work *work)
+static void dpu_encoder_off_work(struct work_struct *work)
{
struct dpu_encoder_virt *dpu_enc = container_of(work,
struct dpu_encoder_virt, delayed_off_work.work);
@@ -1756,15 +1745,14 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
}
-void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
- struct dpu_encoder_kickoff_params *params, bool async)
+void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async)
{
struct dpu_encoder_virt *dpu_enc;
struct dpu_encoder_phys *phys;
bool needs_hw_reset = false;
unsigned int i;
- if (!drm_enc || !params) {
+ if (!drm_enc) {
DPU_ERROR("invalid args\n");
return;
}
@@ -1778,7 +1766,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
phys = dpu_enc->phys_encs[i];
if (phys) {
if (phys->ops.prepare_for_kickoff)
- phys->ops.prepare_for_kickoff(phys, params);
+ phys->ops.prepare_for_kickoff(phys);
if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET)
needs_hw_reset = true;
}
@@ -2193,7 +2181,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc,
mutex_init(&dpu_enc->rc_lock);
- kthread_init_delayed_work(&dpu_enc->delayed_off_work,
+ INIT_DELAYED_WORK(&dpu_enc->delayed_off_work,
dpu_encoder_off_work);
dpu_enc->idle_timeout = IDLE_TIMEOUT;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 3f5dafe00580..d77f74fb26d4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -38,15 +38,6 @@ struct dpu_encoder_hw_resources {
};
/**
- * dpu_encoder_kickoff_params - info encoder requires at kickoff
- * @affected_displays: bitmask, bit set means the ROI of the commit lies within
- * the bounds of the physical display at the bit index
- */
-struct dpu_encoder_kickoff_params {
- unsigned long affected_displays;
-};
-
-/**
* dpu_encoder_get_hw_resources - Populate table of required hardware resources
* @encoder: encoder pointer
* @hw_res: resource table to populate with encoder required resources
@@ -88,11 +79,9 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder,
* Immediately: if no previous commit is outstanding.
* Delayed: Block until next trigger can be issued.
* @encoder: encoder pointer
- * @params: kickoff time parameters
* @async: true if this is an asynchronous commit
*/
-void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder,
- struct dpu_encoder_kickoff_params *params, bool async);
+void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, bool async);
/**
* dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 44e6f8b68e70..db94f3d3bea3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -144,8 +144,7 @@ struct dpu_encoder_phys_ops {
int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc);
int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc);
int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc);
- void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc,
- struct dpu_encoder_kickoff_params *params);
+ void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
index 99ab5ca9bed3..a399e1edd313 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
@@ -594,8 +594,7 @@ static void dpu_encoder_phys_cmd_get_hw_resources(
}
static void dpu_encoder_phys_cmd_prepare_for_kickoff(
- struct dpu_encoder_phys *phys_enc,
- struct dpu_encoder_kickoff_params *params)
+ struct dpu_encoder_phys *phys_enc)
{
struct dpu_encoder_phys_cmd *cmd_enc =
to_dpu_encoder_phys_cmd(phys_enc);
@@ -693,7 +692,7 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done(
/* required for both controllers */
if (!rc && cmd_enc->serialize_wait4pp)
- dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL);
+ dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc);
return rc;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index acdab5b0db18..3c4eb470a82c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -587,14 +587,13 @@ static int dpu_encoder_phys_vid_wait_for_vblank(
}
static void dpu_encoder_phys_vid_prepare_for_kickoff(
- struct dpu_encoder_phys *phys_enc,
- struct dpu_encoder_kickoff_params *params)
+ struct dpu_encoder_phys *phys_enc)
{
struct dpu_encoder_phys_vid *vid_enc;
struct dpu_hw_ctl *ctl;
int rc;
- if (!phys_enc || !params) {
+ if (!phys_enc) {
DPU_ERROR("invalid encoder/parameters\n");
return;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index 0874f0a53bf9..f59fe1a9f4b9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -263,13 +263,13 @@ static const struct dpu_format dpu_format_map[] = {
INTERLEAVED_RGB_FMT(RGB565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, 0,
DPU_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
false, 2, 0,
DPU_FETCH_LINEAR, 1),
@@ -1137,36 +1137,3 @@ const struct msm_format *dpu_get_msm_format(
return &fmt->base;
return NULL;
}
-
-uint32_t dpu_populate_formats(
- const struct dpu_format_extended *format_list,
- uint32_t *pixel_formats,
- uint64_t *pixel_modifiers,
- uint32_t pixel_formats_max)
-{
- uint32_t i, fourcc_format;
-
- if (!format_list || !pixel_formats)
- return 0;
-
- for (i = 0, fourcc_format = 0;
- format_list->fourcc_format && i < pixel_formats_max;
- ++format_list) {
- /* verify if listed format is in dpu_format_map? */
-
- /* optionally return modified formats */
- if (pixel_modifiers) {
- /* assume same modifier for all fb planes */
- pixel_formats[i] = format_list->fourcc_format;
- pixel_modifiers[i++] = format_list->modifier;
- } else {
- /* assume base formats grouped together */
- if (fourcc_format != format_list->fourcc_format) {
- fourcc_format = format_list->fourcc_format;
- pixel_formats[i++] = fourcc_format;
- }
- }
- }
-
- return i;
-}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h
index a54451d8d011..c02c81e7a667 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h
@@ -41,20 +41,6 @@ const struct msm_format *dpu_get_msm_format(
const uint64_t modifiers);
/**
- * dpu_populate_formats - populate the given array with fourcc codes supported
- * @format_list: pointer to list of possible formats
- * @pixel_formats: array to populate with fourcc codes
- * @pixel_modifiers: array to populate with drm modifiers, can be NULL
- * @pixel_formats_max: length of pixel formats array
- * Return: number of elements populated
- */
-uint32_t dpu_populate_formats(
- const struct dpu_format_extended *format_list,
- uint32_t *pixel_formats,
- uint64_t *pixel_modifiers,
- uint32_t pixel_formats_max);
-
-/**
* dpu_format_check_modified_format - validate format and buffers for
* dpu non-standard, i.e. modified format
* @kms: kms driver
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 512ac0834d2b..df6852cc98b9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -151,7 +151,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = {
.id = DPU_SSPP_CSC_10BIT, \
.base = 0x1a00, .len = 0x100,}, \
.format_list = plane_formats_yuv, \
+ .num_formats = ARRAY_SIZE(plane_formats_yuv), \
.virt_format_list = plane_formats, \
+ .virt_num_formats = ARRAY_SIZE(plane_formats), \
}
#define _DMA_SBLK(num, sdma_pri) \
@@ -163,7 +165,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = {
.src_blk = {.name = STRCAT("sspp_src_", num), \
.id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \
.format_list = plane_formats, \
+ .num_formats = ARRAY_SIZE(plane_formats), \
.virt_format_list = plane_formats, \
+ .virt_num_formats = ARRAY_SIZE(plane_formats), \
}
static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 144358a3d0fb..a55653b2e466 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -252,17 +252,6 @@ struct dpu_pp_blk {
};
/**
- * struct dpu_format_extended - define dpu specific pixel format+modifier
- * @fourcc_format: Base FOURCC pixel format code
- * @modifier: 64-bit drm format modifier, same modifier must be applied to all
- * framebuffer planes
- */
-struct dpu_format_extended {
- uint32_t fourcc_format;
- uint64_t modifier;
-};
-
-/**
* enum dpu_qos_lut_usage - define QoS LUT use cases
*/
enum dpu_qos_lut_usage {
@@ -348,7 +337,9 @@ struct dpu_sspp_blks_common {
* @pcc_blk:
* @igc_blk:
* @format_list: Pointer to list of supported formats
+ * @num_formats: Number of supported formats
* @virt_format_list: Pointer to list of supported formats for virtual planes
+ * @virt_num_formats: Number of supported formats for virtual planes
*/
struct dpu_sspp_sub_blks {
const struct dpu_sspp_blks_common *common;
@@ -366,8 +357,10 @@ struct dpu_sspp_sub_blks {
struct dpu_pp_blk pcc_blk;
struct dpu_pp_blk igc_blk;
- const struct dpu_format_extended *format_list;
- const struct dpu_format_extended *virt_format_list;
+ const u32 *format_list;
+ u32 num_formats;
+ const u32 *virt_format_list;
+ u32 virt_num_formats;
};
/**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h
index 3c9f028628ef..d09730985951 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h
@@ -12,157 +12,81 @@
#include "dpu_hw_mdss.h"
-static const struct dpu_format_extended plane_formats[] = {
- {DRM_FORMAT_ARGB8888, 0},
- {DRM_FORMAT_ABGR8888, 0},
- {DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_BGRA8888, 0},
- {DRM_FORMAT_XRGB8888, 0},
- {DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_BGRX8888, 0},
- {DRM_FORMAT_XBGR8888, 0},
- {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_RGB888, 0},
- {DRM_FORMAT_BGR888, 0},
- {DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_BGR565, 0},
- {DRM_FORMAT_ARGB1555, 0},
- {DRM_FORMAT_ABGR1555, 0},
- {DRM_FORMAT_RGBA5551, 0},
- {DRM_FORMAT_BGRA5551, 0},
- {DRM_FORMAT_XRGB1555, 0},
- {DRM_FORMAT_XBGR1555, 0},
- {DRM_FORMAT_RGBX5551, 0},
- {DRM_FORMAT_BGRX5551, 0},
- {DRM_FORMAT_ARGB4444, 0},
- {DRM_FORMAT_ABGR4444, 0},
- {DRM_FORMAT_RGBA4444, 0},
- {DRM_FORMAT_BGRA4444, 0},
- {DRM_FORMAT_XRGB4444, 0},
- {DRM_FORMAT_XBGR4444, 0},
- {DRM_FORMAT_RGBX4444, 0},
- {DRM_FORMAT_BGRX4444, 0},
- {0, 0},
+static const uint32_t qcom_compressed_supported_formats[] = {
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_BGR565,
};
-static const struct dpu_format_extended plane_formats_yuv[] = {
- {DRM_FORMAT_ARGB8888, 0},
- {DRM_FORMAT_ABGR8888, 0},
- {DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_BGRX8888, 0},
- {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_BGRA8888, 0},
- {DRM_FORMAT_XRGB8888, 0},
- {DRM_FORMAT_XBGR8888, 0},
- {DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_RGB888, 0},
- {DRM_FORMAT_BGR888, 0},
- {DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_BGR565, 0},
- {DRM_FORMAT_ARGB1555, 0},
- {DRM_FORMAT_ABGR1555, 0},
- {DRM_FORMAT_RGBA5551, 0},
- {DRM_FORMAT_BGRA5551, 0},
- {DRM_FORMAT_XRGB1555, 0},
- {DRM_FORMAT_XBGR1555, 0},
- {DRM_FORMAT_RGBX5551, 0},
- {DRM_FORMAT_BGRX5551, 0},
- {DRM_FORMAT_ARGB4444, 0},
- {DRM_FORMAT_ABGR4444, 0},
- {DRM_FORMAT_RGBA4444, 0},
- {DRM_FORMAT_BGRA4444, 0},
- {DRM_FORMAT_XRGB4444, 0},
- {DRM_FORMAT_XBGR4444, 0},
- {DRM_FORMAT_RGBX4444, 0},
- {DRM_FORMAT_BGRX4444, 0},
-
- {DRM_FORMAT_NV12, 0},
- {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_NV21, 0},
- {DRM_FORMAT_NV16, 0},
- {DRM_FORMAT_NV61, 0},
- {DRM_FORMAT_VYUY, 0},
- {DRM_FORMAT_UYVY, 0},
- {DRM_FORMAT_YUYV, 0},
- {DRM_FORMAT_YVYU, 0},
- {DRM_FORMAT_YUV420, 0},
- {DRM_FORMAT_YVU420, 0},
- {0, 0},
-};
-
-static const struct dpu_format_extended cursor_formats[] = {
- {DRM_FORMAT_ARGB8888, 0},
- {DRM_FORMAT_ABGR8888, 0},
- {DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_BGRA8888, 0},
- {DRM_FORMAT_XRGB8888, 0},
- {DRM_FORMAT_ARGB1555, 0},
- {DRM_FORMAT_ABGR1555, 0},
- {DRM_FORMAT_RGBA5551, 0},
- {DRM_FORMAT_BGRA5551, 0},
- {DRM_FORMAT_ARGB4444, 0},
- {DRM_FORMAT_ABGR4444, 0},
- {DRM_FORMAT_RGBA4444, 0},
- {DRM_FORMAT_BGRA4444, 0},
- {0, 0},
+static const uint32_t plane_formats[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XBGR1555,
+ DRM_FORMAT_RGBX5551,
+ DRM_FORMAT_BGRX5551,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_XBGR4444,
+ DRM_FORMAT_RGBX4444,
+ DRM_FORMAT_BGRX4444,
};
-static const struct dpu_format_extended wb2_formats[] = {
- {DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_RGB888, 0},
- {DRM_FORMAT_ARGB8888, 0},
- {DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_XRGB8888, 0},
- {DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_ARGB1555, 0},
- {DRM_FORMAT_RGBA5551, 0},
- {DRM_FORMAT_XRGB1555, 0},
- {DRM_FORMAT_RGBX5551, 0},
- {DRM_FORMAT_ARGB4444, 0},
- {DRM_FORMAT_RGBA4444, 0},
- {DRM_FORMAT_RGBX4444, 0},
- {DRM_FORMAT_XRGB4444, 0},
-
- {DRM_FORMAT_BGR565, 0},
- {DRM_FORMAT_BGR888, 0},
- {DRM_FORMAT_ABGR8888, 0},
- {DRM_FORMAT_BGRA8888, 0},
- {DRM_FORMAT_BGRX8888, 0},
- {DRM_FORMAT_XBGR8888, 0},
- {DRM_FORMAT_ABGR1555, 0},
- {DRM_FORMAT_BGRA5551, 0},
- {DRM_FORMAT_XBGR1555, 0},
- {DRM_FORMAT_BGRX5551, 0},
- {DRM_FORMAT_ABGR4444, 0},
- {DRM_FORMAT_BGRA4444, 0},
- {DRM_FORMAT_BGRX4444, 0},
- {DRM_FORMAT_XBGR4444, 0},
-
- {DRM_FORMAT_YUV420, 0},
- {DRM_FORMAT_NV12, 0},
- {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_NV16, 0},
- {DRM_FORMAT_YUYV, 0},
-
- {0, 0},
-};
+static const uint32_t plane_formats_yuv[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XBGR1555,
+ DRM_FORMAT_RGBX5551,
+ DRM_FORMAT_BGRX5551,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_XBGR4444,
+ DRM_FORMAT_RGBX4444,
+ DRM_FORMAT_BGRX4444,
-static const struct dpu_format_extended rgb_10bit_formats[] = {
- {DRM_FORMAT_BGRA1010102, 0},
- {DRM_FORMAT_BGRX1010102, 0},
- {DRM_FORMAT_RGBA1010102, 0},
- {DRM_FORMAT_RGBX1010102, 0},
- {DRM_FORMAT_ABGR2101010, 0},
- {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_XBGR2101010, 0},
- {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
- {DRM_FORMAT_ARGB2101010, 0},
- {DRM_FORMAT_XRGB2101010, 0},
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_YVU420,
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index c0b7f0049365..8a28a03ac6a9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -170,10 +170,6 @@
/**
* AD4 interrupt status bit definitions
*/
-#define DPU_INTR_BRIGHTPR_UPDATED BIT(4)
-#define DPU_INTR_DARKENH_UPDATED BIT(3)
-#define DPU_INTR_STREN_OUTROI_UPDATED BIT(2)
-#define DPU_INTR_STREN_INROI_UPDATED BIT(1)
#define DPU_INTR_BACKLIGHT_UPDATED BIT(0)
/**
* struct dpu_intr_reg - array of DPU register sets
@@ -782,18 +778,6 @@ static int dpu_hw_intr_irqidx_lookup(enum dpu_intr_type intr_type,
return -EINVAL;
}
-static void dpu_hw_intr_set_mask(struct dpu_hw_intr *intr, uint32_t reg_off,
- uint32_t mask)
-{
- if (!intr)
- return;
-
- DPU_REG_WRITE(&intr->hw, reg_off, mask);
-
- /* ensure register writes go through */
- wmb();
-}
-
static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr,
void (*cbfunc)(void *, int),
void *arg)
@@ -1004,18 +988,6 @@ static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr)
return 0;
}
-static int dpu_hw_intr_get_valid_interrupts(struct dpu_hw_intr *intr,
- uint32_t *mask)
-{
- if (!intr || !mask)
- return -EINVAL;
-
- *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1
- | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP;
-
- return 0;
-}
-
static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr)
{
int i;
@@ -1065,19 +1037,6 @@ static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr,
wmb();
}
-static void dpu_hw_intr_clear_interrupt_status(struct dpu_hw_intr *intr,
- int irq_idx)
-{
- unsigned long irq_flags;
-
- if (!intr)
- return;
-
- spin_lock_irqsave(&intr->irq_lock, irq_flags);
- dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx);
- spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
-}
-
static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr,
int irq_idx, bool clear)
{
@@ -1113,16 +1072,13 @@ static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr,
static void __setup_intr_ops(struct dpu_hw_intr_ops *ops)
{
- ops->set_mask = dpu_hw_intr_set_mask;
ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup;
ops->enable_irq = dpu_hw_intr_enable_irq;
ops->disable_irq = dpu_hw_intr_disable_irq;
ops->dispatch_irqs = dpu_hw_intr_dispatch_irq;
ops->clear_all_irqs = dpu_hw_intr_clear_irqs;
ops->disable_all_irqs = dpu_hw_intr_disable_irqs;
- ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts;
ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses;
- ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status;
ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock;
ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 61e4cba36562..4d7a1c727ce2 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -20,13 +20,6 @@
#include "dpu_hw_util.h"
#include "dpu_hw_mdss.h"
-#define IRQ_SOURCE_MDP BIT(0)
-#define IRQ_SOURCE_DSI0 BIT(4)
-#define IRQ_SOURCE_DSI1 BIT(5)
-#define IRQ_SOURCE_HDMI BIT(8)
-#define IRQ_SOURCE_EDP BIT(12)
-#define IRQ_SOURCE_MHL BIT(16)
-
/**
* dpu_intr_type - HW Interrupt Type
* @DPU_IRQ_TYPE_WB_ROT_COMP: WB rotator done
@@ -96,18 +89,6 @@ struct dpu_hw_intr;
*/
struct dpu_hw_intr_ops {
/**
- * set_mask - Programs the given interrupt register with the
- * given interrupt mask. Register value will get overwritten.
- * @intr: HW interrupt handle
- * @reg_off: MDSS HW register offset
- * @irqmask: IRQ mask value
- */
- void (*set_mask)(
- struct dpu_hw_intr *intr,
- uint32_t reg,
- uint32_t irqmask);
-
- /**
* irq_idx_lookup - Lookup IRQ index on the HW interrupt type
* Used for all irq related ops
* @intr_type: Interrupt type defined in dpu_intr_type
@@ -177,16 +158,6 @@ struct dpu_hw_intr_ops {
struct dpu_hw_intr *intr);
/**
- * clear_interrupt_status - Clears HW interrupt status based on given
- * lookup IRQ index.
- * @intr: HW interrupt handle
- * @irq_idx: Lookup irq index return from irq_idx_lookup
- */
- void (*clear_interrupt_status)(
- struct dpu_hw_intr *intr,
- int irq_idx);
-
- /**
* clear_intr_status_nolock() - clears the HW interrupts without lock
* @intr: HW interrupt handle
* @irq_idx: Lookup irq index return from irq_idx_lookup
@@ -206,21 +177,6 @@ struct dpu_hw_intr_ops {
struct dpu_hw_intr *intr,
int irq_idx,
bool clear);
-
- /**
- * get_valid_interrupts - Gets a mask of all valid interrupt sources
- * within DPU. These are actually status bits
- * within interrupt registers that specify the
- * source of the interrupt in IRQs. For example,
- * valid interrupt sources can be MDP, DSI,
- * HDMI etc.
- * @intr: HW interrupt handle
- * @mask: Returning the interrupt source MASK
- * @return: 0 for success, otherwise failure
- */
- int (*get_valid_interrupts)(
- struct dpu_hw_intr *intr,
- uint32_t *mask);
};
/**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 68c54d2c9677..1ab8d4a889f7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -258,12 +258,6 @@ enum dpu_vbif {
VBIF_NRT = VBIF_1
};
-enum dpu_iommu_domain {
- DPU_IOMMU_DOMAIN_UNSECURE,
- DPU_IOMMU_DOMAIN_SECURE,
- DPU_IOMMU_DOMAIN_MAX
-};
-
/**
* DPU HW,Component order color map
*/
@@ -358,7 +352,6 @@ enum dpu_3d_blend_mode {
* @alpha_enable: whether the format has an alpha channel
* @num_planes: number of planes (including meta data planes)
* @fetch_mode: linear, tiled, or ubwc hw fetch behavior
- * @is_yuv: is format a yuv variant
* @flag: usage bit flags
* @tile_width: format tile width
* @tile_height: format tile height
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
index 321fc64ddd0e..efe70c508ee0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
@@ -18,7 +18,6 @@
#include "dpu_hw_mdss.h"
#define REG_MASK(n) ((BIT(n)) - 1)
-struct dpu_format_extended;
/*
* This is the common struct maintained by each sub block
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 4d67b3c96702..885bf88afa3e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -405,35 +405,38 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms,
}
}
-static void _dpu_kms_initialize_dsi(struct drm_device *dev,
+static int _dpu_kms_initialize_dsi(struct drm_device *dev,
struct msm_drm_private *priv,
struct dpu_kms *dpu_kms)
{
struct drm_encoder *encoder = NULL;
- int i, rc;
+ int i, rc = 0;
+
+ if (!(priv->dsi[0] || priv->dsi[1]))
+ return rc;
/*TODO: Support two independent DSI connectors */
encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI);
- if (IS_ERR_OR_NULL(encoder)) {
+ if (IS_ERR(encoder)) {
DPU_ERROR("encoder init failed for dsi display\n");
- return;
+ return PTR_ERR(encoder);
}
priv->encoders[priv->num_encoders++] = encoder;
for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {
- if (!priv->dsi[i]) {
- DPU_DEBUG("invalid msm_dsi for ctrl %d\n", i);
- return;
- }
+ if (!priv->dsi[i])
+ continue;
rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder);
if (rc) {
DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n",
i, rc);
- continue;
+ break;
}
}
+
+ return rc;
}
/**
@@ -444,16 +447,16 @@ static void _dpu_kms_initialize_dsi(struct drm_device *dev,
* @dpu_kms: Pointer to dpu kms structure
* Returns: Zero on success
*/
-static void _dpu_kms_setup_displays(struct drm_device *dev,
+static int _dpu_kms_setup_displays(struct drm_device *dev,
struct msm_drm_private *priv,
struct dpu_kms *dpu_kms)
{
- _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
-
/**
* Extend this function to initialize other
* types of displays
*/
+
+ return _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
}
static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms)
@@ -516,7 +519,9 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
* Create encoder and query display drivers to create
* bridges and connectors
*/
- _dpu_kms_setup_displays(dev, priv, dpu_kms);
+ ret = _dpu_kms_setup_displays(dev, priv, dpu_kms);
+ if (ret)
+ goto fail;
max_crtc_count = min(catalog->mixer_count, priv->num_encoders);
@@ -627,6 +632,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)
devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]);
dpu_kms->vbif[VBIF_RT] = NULL;
+ if (dpu_kms->hw_mdp)
+ dpu_hw_mdp_destroy(dpu_kms->hw_mdp);
+ dpu_kms->hw_mdp = NULL;
+
if (dpu_kms->mmio)
devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio);
dpu_kms->mmio = NULL;
@@ -877,8 +886,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
goto power_error;
}
- rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio,
- dpu_kms->dev);
+ rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio);
if (rc) {
DPU_ERROR("rm init failed: %d\n", rc);
goto power_error;
@@ -886,11 +894,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
dpu_kms->rm_init = true;
- dpu_kms->hw_mdp = dpu_rm_get_mdp(&dpu_kms->rm);
- if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) {
+ dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
+ dpu_kms->catalog);
+ if (IS_ERR(dpu_kms->hw_mdp)) {
rc = PTR_ERR(dpu_kms->hw_mdp);
- if (!dpu_kms->hw_mdp)
- rc = -EINVAL;
DPU_ERROR("failed to get hw_mdp: %d\n", rc);
dpu_kms->hw_mdp = NULL;
goto power_error;
@@ -926,16 +933,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
goto hw_intr_init_err;
}
- /*
- * _dpu_kms_drm_obj_init should create the DRM related objects
- * i.e. CRTCs, planes, encoders, connectors and so forth
- */
- rc = _dpu_kms_drm_obj_init(dpu_kms);
- if (rc) {
- DPU_ERROR("modeset init failed: %d\n", rc);
- goto drm_obj_init_err;
- }
-
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -952,6 +949,16 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
*/
dev->mode_config.allow_fb_modifiers = true;
+ /*
+ * _dpu_kms_drm_obj_init should create the DRM related objects
+ * i.e. CRTCs, planes, encoders, connectors and so forth
+ */
+ rc = _dpu_kms_drm_obj_init(dpu_kms);
+ if (rc) {
+ DPU_ERROR("modeset init failed: %d\n", rc);
+ goto drm_obj_init_err;
+ }
+
dpu_vbif_init_memtypes(dpu_kms);
pm_runtime_put_sync(&dpu_kms->pdev->dev);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
index cb307a2abf06..7316b4ab1b85 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
@@ -23,11 +23,14 @@ struct dpu_mdss {
struct dpu_irq_controller irq_controller;
};
-static irqreturn_t dpu_mdss_irq(int irq, void *arg)
+static void dpu_mdss_irq(struct irq_desc *desc)
{
- struct dpu_mdss *dpu_mdss = arg;
+ struct dpu_mdss *dpu_mdss = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
u32 interrupts;
+ chained_irq_enter(chip, desc);
+
interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS);
while (interrupts) {
@@ -39,20 +42,20 @@ static irqreturn_t dpu_mdss_irq(int irq, void *arg)
hwirq);
if (mapping == 0) {
DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq);
- return IRQ_NONE;
+ break;
}
rc = generic_handle_irq(mapping);
if (rc < 0) {
DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n",
hwirq, mapping, rc);
- return IRQ_NONE;
+ break;
}
interrupts &= ~(1 << hwirq);
}
- return IRQ_HANDLED;
+ chained_irq_exit(chip, desc);
}
static void dpu_mdss_irq_mask(struct irq_data *irqd)
@@ -83,16 +86,16 @@ static struct irq_chip dpu_mdss_irq_chip = {
.irq_unmask = dpu_mdss_irq_unmask,
};
+static struct lock_class_key dpu_mdss_lock_key, dpu_mdss_request_key;
+
static int dpu_mdss_irqdomain_map(struct irq_domain *domain,
unsigned int irq, irq_hw_number_t hwirq)
{
struct dpu_mdss *dpu_mdss = domain->host_data;
- int ret;
+ irq_set_lockdep_class(irq, &dpu_mdss_lock_key, &dpu_mdss_request_key);
irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq);
- ret = irq_set_chip_data(irq, dpu_mdss);
-
- return ret;
+ return irq_set_chip_data(irq, dpu_mdss);
}
static const struct irq_domain_ops dpu_mdss_irqdomain_ops = {
@@ -159,11 +162,13 @@ static void dpu_mdss_destroy(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss);
struct dss_module_power *mp = &dpu_mdss->mp;
+ int irq;
pm_runtime_suspend(dev->dev);
pm_runtime_disable(dev->dev);
_dpu_mdss_irq_domain_fini(dpu_mdss);
- free_irq(platform_get_irq(pdev, 0), dpu_mdss);
+ irq = platform_get_irq(pdev, 0);
+ irq_set_chained_handler_and_data(irq, NULL, NULL);
msm_dss_put_clk(mp->clk_config, mp->num_clk);
devm_kfree(&pdev->dev, mp->clk_config);
@@ -187,6 +192,7 @@ int dpu_mdss_init(struct drm_device *dev)
struct dpu_mdss *dpu_mdss;
struct dss_module_power *mp;
int ret = 0;
+ int irq;
dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL);
if (!dpu_mdss)
@@ -219,12 +225,12 @@ int dpu_mdss_init(struct drm_device *dev)
if (ret)
goto irq_domain_error;
- ret = request_irq(platform_get_irq(pdev, 0),
- dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss);
- if (ret) {
- DPU_ERROR("failed to init irq: %d\n", ret);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
goto irq_error;
- }
+
+ irq_set_chained_handler_and_data(irq, dpu_mdss_irq,
+ dpu_mdss);
pm_runtime_enable(dev->dev);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index fd75870eb17f..b01183b309b9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -95,8 +95,6 @@ struct dpu_plane {
enum dpu_sspp pipe;
uint32_t features; /* capabilities from catalog */
- uint32_t nformats;
- uint32_t formats[64];
struct dpu_hw_pipe *pipe_hw;
struct dpu_hw_pipe_cfg pipe_cfg;
@@ -121,6 +119,12 @@ struct dpu_plane {
bool debugfs_default_scale;
};
+static const uint64_t supported_format_modifiers[] = {
+ DRM_FORMAT_MOD_QCOM_COMPRESSED,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
#define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane)
@@ -365,19 +369,6 @@ static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane,
&pdpu->pipe_qos_cfg);
}
-static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
-{
- struct dpu_plane *pdpu = to_dpu_plane(plane);
- struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
-
- if (!pdpu->is_rt_pipe)
- return;
-
- pm_runtime_get_sync(&dpu_kms->pdev->dev);
- _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL);
- pm_runtime_put_sync(&dpu_kms->pdev->dev);
-}
-
/**
* _dpu_plane_set_ot_limit - set OT limit for the given plane
* @plane: Pointer to drm plane
@@ -1248,6 +1239,19 @@ static void dpu_plane_reset(struct drm_plane *plane)
}
#ifdef CONFIG_DEBUG_FS
+static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
+{
+ struct dpu_plane *pdpu = to_dpu_plane(plane);
+ struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
+
+ if (!pdpu->is_rt_pipe)
+ return;
+
+ pm_runtime_get_sync(&dpu_kms->pdev->dev);
+ _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL);
+ pm_runtime_put_sync(&dpu_kms->pdev->dev);
+}
+
static ssize_t _dpu_plane_danger_read(struct file *file,
char __user *buff, size_t count, loff_t *ppos)
{
@@ -1410,6 +1414,23 @@ static void dpu_plane_early_unregister(struct drm_plane *plane)
debugfs_remove_recursive(pdpu->debugfs_root);
}
+static bool dpu_plane_format_mod_supported(struct drm_plane *plane,
+ uint32_t format, uint64_t modifier)
+{
+ if (modifier == DRM_FORMAT_MOD_LINEAR)
+ return true;
+
+ if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(qcom_compressed_supported_formats); i++) {
+ if (format == qcom_compressed_supported_formats[i])
+ return true;
+ }
+ }
+
+ return false;
+}
+
static const struct drm_plane_funcs dpu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -1419,6 +1440,7 @@ static const struct drm_plane_funcs dpu_plane_funcs = {
.atomic_destroy_state = dpu_plane_destroy_state,
.late_register = dpu_plane_late_register,
.early_unregister = dpu_plane_early_unregister,
+ .format_mod_supported = dpu_plane_format_mod_supported,
};
static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
@@ -1444,11 +1466,12 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
unsigned long possible_crtcs, u32 master_plane_id)
{
struct drm_plane *plane = NULL, *master_plane = NULL;
- const struct dpu_format_extended *format_list;
+ const uint32_t *format_list;
struct dpu_plane *pdpu;
struct msm_drm_private *priv = dev->dev_private;
struct dpu_kms *kms = to_dpu_kms(priv->kms);
int zpos_max = DPU_ZPOS_MAX;
+ uint32_t num_formats;
int ret = -EINVAL;
/* create and zero local structure */
@@ -1491,24 +1514,18 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
goto clean_sspp;
}
- if (!master_plane_id)
- format_list = pdpu->pipe_sblk->format_list;
- else
+ if (pdpu->is_virtual) {
format_list = pdpu->pipe_sblk->virt_format_list;
-
- pdpu->nformats = dpu_populate_formats(format_list,
- pdpu->formats,
- 0,
- ARRAY_SIZE(pdpu->formats));
-
- if (!pdpu->nformats) {
- DPU_ERROR("[%u]no valid formats for plane\n", pipe);
- goto clean_sspp;
+ num_formats = pdpu->pipe_sblk->virt_num_formats;
+ }
+ else {
+ format_list = pdpu->pipe_sblk->format_list;
+ num_formats = pdpu->pipe_sblk->num_formats;
}
ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs,
- pdpu->formats, pdpu->nformats,
- NULL, type, NULL);
+ format_list, num_formats,
+ supported_format_modifiers, type, NULL);
if (ret)
goto clean_sspp;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 7fed0b627708..0e6063acd041 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -28,23 +28,18 @@
/**
* struct dpu_plane_state: Define dpu extension of drm plane state object
* @base: base drm plane state object
- * @property_state: Local storage for msm_prop properties
- * @property_values: cached plane property values
* @aspace: pointer to address space for input/output buffers
- * @input_fence: dereferenced input fence pointer
* @stage: assigned by crtc blender
* @multirect_index: index of the rectangle of SSPP
* @multirect_mode: parallel or time multiplex multirect mode
* @pending: whether the current update is still pending
* @scaler3_cfg: configuration data for scaler3
* @pixel_ext: configuration data for pixel extensions
- * @scaler_check_state: indicates status of user provided pixel extension data
* @cdp_cfg: CDP configuration
*/
struct dpu_plane_state {
struct drm_plane_state base;
struct msm_gem_address_space *aspace;
- void *input_fence;
enum dpu_stage stage;
uint32_t multirect_index;
uint32_t multirect_mode;
@@ -107,12 +102,6 @@ void dpu_plane_restore(struct drm_plane *plane);
void dpu_plane_flush(struct drm_plane *plane);
/**
- * dpu_plane_kickoff - final plane operations before commit kickoff
- * @plane: Pointer to drm plane structure
- */
-void dpu_plane_kickoff(struct drm_plane *plane);
-
-/**
* dpu_plane_set_error: enable/disable error condition
* @plane: pointer to drm_plane structure
*/
@@ -147,14 +136,6 @@ int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane);
void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state);
/**
- * dpu_plane_wait_input_fence - wait for input fence object
- * @plane: Pointer to DRM plane object
- * @wait_ms: Wait timeout value
- * Returns: Zero on success
- */
-int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms);
-
-/**
* dpu_plane_color_fill - enables color fill on plane
* @plane: Pointer to DRM plane object
* @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
@@ -164,12 +145,4 @@ int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms);
int dpu_plane_color_fill(struct drm_plane *plane,
uint32_t color, uint32_t alpha);
-/**
- * dpu_plane_set_revalidate - sets revalidate flag which forces a full
- * validation of the plane properties in the next atomic check
- * @plane: Pointer to DRM plane object
- * @enable: Boolean to set/unset the flag
- */
-void dpu_plane_set_revalidate(struct drm_plane *plane, bool enable);
-
#endif /* _DPU_PLANE_H_ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index bdb117709674..037d9f4187f9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -21,8 +21,8 @@
#include "dpu_encoder.h"
#include "dpu_trace.h"
-#define RESERVED_BY_OTHER(h, r) \
- ((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id))
+#define RESERVED_BY_OTHER(h, r) \
+ ((h)->enc_id && (h)->enc_id != r)
/**
* struct dpu_rm_requirements - Reservation requirements parameter bundle
@@ -34,90 +34,21 @@ struct dpu_rm_requirements {
struct dpu_encoder_hw_resources hw_res;
};
-/**
- * struct dpu_rm_rsvp - Use Case Reservation tagging structure
- * Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain
- * By using as a tag, rather than lists of pointers to HW blocks used
- * we can avoid some list management since we don't know how many blocks
- * of each type a given use case may require.
- * @list: List head for list of all reservations
- * @seq: Global RSVP sequence number for debugging, especially for
- * differentiating differenct allocations for same encoder.
- * @enc_id: Reservations are tracked by Encoder DRM object ID.
- * CRTCs may be connected to multiple Encoders.
- * An encoder or connector id identifies the display path.
- */
-struct dpu_rm_rsvp {
- struct list_head list;
- uint32_t seq;
- uint32_t enc_id;
-};
/**
* struct dpu_rm_hw_blk - hardware block tracking list member
* @list: List head for list of all hardware blocks tracking items
- * @rsvp: Pointer to use case reservation if reserved by a client
- * @rsvp_nxt: Temporary pointer used during reservation to the incoming
- * request. Will be swapped into rsvp if proposal is accepted
- * @type: Type of hardware block this structure tracks
* @id: Hardware ID number, within it's own space, ie. LM_X
- * @catalog: Pointer to the hardware catalog entry for this block
+ * @enc_id: Encoder id to which this blk is binded
* @hw: Pointer to the hardware register access object for this block
*/
struct dpu_rm_hw_blk {
struct list_head list;
- struct dpu_rm_rsvp *rsvp;
- struct dpu_rm_rsvp *rsvp_nxt;
- enum dpu_hw_blk_type type;
uint32_t id;
+ uint32_t enc_id;
struct dpu_hw_blk *hw;
};
-/**
- * dpu_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging
- */
-enum dpu_rm_dbg_rsvp_stage {
- DPU_RM_STAGE_BEGIN,
- DPU_RM_STAGE_AFTER_CLEAR,
- DPU_RM_STAGE_AFTER_RSVPNEXT,
- DPU_RM_STAGE_FINAL
-};
-
-static void _dpu_rm_print_rsvps(
- struct dpu_rm *rm,
- enum dpu_rm_dbg_rsvp_stage stage)
-{
- struct dpu_rm_rsvp *rsvp;
- struct dpu_rm_hw_blk *blk;
- enum dpu_hw_blk_type type;
-
- DPU_DEBUG("%d\n", stage);
-
- list_for_each_entry(rsvp, &rm->rsvps, list) {
- DRM_DEBUG_KMS("%d rsvp[s%ue%u]\n", stage, rsvp->seq,
- rsvp->enc_id);
- }
-
- for (type = 0; type < DPU_HW_BLK_MAX; type++) {
- list_for_each_entry(blk, &rm->hw_blks[type], list) {
- if (!blk->rsvp && !blk->rsvp_nxt)
- continue;
-
- DRM_DEBUG_KMS("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage,
- (blk->rsvp) ? blk->rsvp->seq : 0,
- (blk->rsvp) ? blk->rsvp->enc_id : 0,
- (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
- (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
- blk->type, blk->id);
- }
- }
-}
-
-struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm)
-{
- return rm->hw_mdp;
-}
-
void dpu_rm_init_hw_iter(
struct dpu_rm_hw_iter *iter,
uint32_t enc_id,
@@ -148,15 +79,7 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i)
i->blk = list_prepare_entry(i->blk, blk_list, list);
list_for_each_entry_continue(i->blk, blk_list, list) {
- struct dpu_rm_rsvp *rsvp = i->blk->rsvp;
-
- if (i->blk->type != i->type) {
- DPU_ERROR("found incorrect block type %d on %d list\n",
- i->blk->type, i->type);
- return false;
- }
-
- if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) {
+ if (i->enc_id == i->blk->enc_id) {
i->hw = i->blk->hw;
DPU_DEBUG("found type %d id %d for enc %d\n",
i->type, i->blk->id, i->enc_id);
@@ -208,34 +131,18 @@ static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw)
int dpu_rm_destroy(struct dpu_rm *rm)
{
-
- struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt;
struct dpu_rm_hw_blk *hw_cur, *hw_nxt;
enum dpu_hw_blk_type type;
- if (!rm) {
- DPU_ERROR("invalid rm\n");
- return -EINVAL;
- }
-
- list_for_each_entry_safe(rsvp_cur, rsvp_nxt, &rm->rsvps, list) {
- list_del(&rsvp_cur->list);
- kfree(rsvp_cur);
- }
-
-
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type],
list) {
list_del(&hw_cur->list);
- _dpu_rm_hw_destroy(hw_cur->type, hw_cur->hw);
+ _dpu_rm_hw_destroy(type, hw_cur->hw);
kfree(hw_cur);
}
}
- dpu_hw_mdp_destroy(rm->hw_mdp);
- rm->hw_mdp = NULL;
-
mutex_destroy(&rm->rm_lock);
return 0;
@@ -250,11 +157,8 @@ static int _dpu_rm_hw_blk_create(
void *hw_catalog_info)
{
struct dpu_rm_hw_blk *blk;
- struct dpu_hw_mdp *hw_mdp;
void *hw;
- hw_mdp = rm->hw_mdp;
-
switch (type) {
case DPU_HW_BLK_LM:
hw = dpu_hw_lm_init(id, mmio, cat);
@@ -290,9 +194,9 @@ static int _dpu_rm_hw_blk_create(
return -ENOMEM;
}
- blk->type = type;
blk->id = id;
blk->hw = hw;
+ blk->enc_id = 0;
list_add_tail(&blk->list, &rm->hw_blks[type]);
return 0;
@@ -300,13 +204,12 @@ static int _dpu_rm_hw_blk_create(
int dpu_rm_init(struct dpu_rm *rm,
struct dpu_mdss_cfg *cat,
- void __iomem *mmio,
- struct drm_device *dev)
+ void __iomem *mmio)
{
int rc, i;
enum dpu_hw_blk_type type;
- if (!rm || !cat || !mmio || !dev) {
+ if (!rm || !cat || !mmio) {
DPU_ERROR("invalid kms\n");
return -EINVAL;
}
@@ -316,21 +219,9 @@ int dpu_rm_init(struct dpu_rm *rm,
mutex_init(&rm->rm_lock);
- INIT_LIST_HEAD(&rm->rsvps);
for (type = 0; type < DPU_HW_BLK_MAX; type++)
INIT_LIST_HEAD(&rm->hw_blks[type]);
- rm->dev = dev;
-
- /* Some of the sub-blocks require an mdptop to be created */
- rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat);
- if (IS_ERR_OR_NULL(rm->hw_mdp)) {
- rc = PTR_ERR(rm->hw_mdp);
- rm->hw_mdp = NULL;
- DPU_ERROR("failed: mdp hw not available\n");
- goto fail;
- }
-
/* Interrogate HW catalog and create tracking items for hw blocks */
for (i = 0; i < cat->mixer_count; i++) {
struct dpu_lm_cfg *lm = &cat->mixer[i];
@@ -410,7 +301,7 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
* proposed use case requirements, incl. hardwired dependent blocks like
* pingpong
* @rm: dpu resource manager handle
- * @rsvp: reservation currently being created
+ * @enc_id: encoder id requesting for allocation
* @reqs: proposed use case requirements
* @lm: proposed layer mixer, function checks if lm, and all other hardwired
* blocks connected to the lm (pp) is available and appropriate
@@ -422,7 +313,7 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top)
*/
static bool _dpu_rm_check_lm_and_get_connected_blks(
struct dpu_rm *rm,
- struct dpu_rm_rsvp *rsvp,
+ uint32_t enc_id,
struct dpu_rm_requirements *reqs,
struct dpu_rm_hw_blk *lm,
struct dpu_rm_hw_blk **pp,
@@ -449,7 +340,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
}
/* Already reserved? */
- if (RESERVED_BY_OTHER(lm, rsvp)) {
+ if (RESERVED_BY_OTHER(lm, enc_id)) {
DPU_DEBUG("lm %d already reserved\n", lm_cfg->id);
return false;
}
@@ -467,7 +358,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
return false;
}
- if (RESERVED_BY_OTHER(*pp, rsvp)) {
+ if (RESERVED_BY_OTHER(*pp, enc_id)) {
DPU_DEBUG("lm %d pp %d already reserved\n", lm->id,
(*pp)->id);
return false;
@@ -476,10 +367,8 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
return true;
}
-static int _dpu_rm_reserve_lms(
- struct dpu_rm *rm,
- struct dpu_rm_rsvp *rsvp,
- struct dpu_rm_requirements *reqs)
+static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id,
+ struct dpu_rm_requirements *reqs)
{
struct dpu_rm_hw_blk *lm[MAX_BLOCKS];
@@ -504,7 +393,7 @@ static int _dpu_rm_reserve_lms(
lm[lm_count] = iter_i.blk;
if (!_dpu_rm_check_lm_and_get_connected_blks(
- rm, rsvp, reqs, lm[lm_count],
+ rm, enc_id, reqs, lm[lm_count],
&pp[lm_count], NULL))
continue;
@@ -519,7 +408,7 @@ static int _dpu_rm_reserve_lms(
continue;
if (!_dpu_rm_check_lm_and_get_connected_blks(
- rm, rsvp, reqs, iter_j.blk,
+ rm, enc_id, reqs, iter_j.blk,
&pp[lm_count], iter_i.blk))
continue;
@@ -537,11 +426,10 @@ static int _dpu_rm_reserve_lms(
if (!lm[i])
break;
- lm[i]->rsvp_nxt = rsvp;
- pp[i]->rsvp_nxt = rsvp;
+ lm[i]->enc_id = enc_id;
+ pp[i]->enc_id = enc_id;
- trace_dpu_rm_reserve_lms(lm[i]->id, lm[i]->type, rsvp->enc_id,
- pp[i]->id);
+ trace_dpu_rm_reserve_lms(lm[i]->id, enc_id, pp[i]->id);
}
return rc;
@@ -549,7 +437,7 @@ static int _dpu_rm_reserve_lms(
static int _dpu_rm_reserve_ctls(
struct dpu_rm *rm,
- struct dpu_rm_rsvp *rsvp,
+ uint32_t enc_id,
const struct msm_display_topology *top)
{
struct dpu_rm_hw_blk *ctls[MAX_BLOCKS];
@@ -570,7 +458,7 @@ static int _dpu_rm_reserve_ctls(
unsigned long features = ctl->caps->features;
bool has_split_display;
- if (RESERVED_BY_OTHER(iter.blk, rsvp))
+ if (RESERVED_BY_OTHER(iter.blk, enc_id))
continue;
has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features;
@@ -591,9 +479,8 @@ static int _dpu_rm_reserve_ctls(
return -ENAVAIL;
for (i = 0; i < ARRAY_SIZE(ctls) && i < num_ctls; i++) {
- ctls[i]->rsvp_nxt = rsvp;
- trace_dpu_rm_reserve_ctls(ctls[i]->id, ctls[i]->type,
- rsvp->enc_id);
+ ctls[i]->enc_id = enc_id;
+ trace_dpu_rm_reserve_ctls(ctls[i]->id, enc_id);
}
return 0;
@@ -601,7 +488,7 @@ static int _dpu_rm_reserve_ctls(
static int _dpu_rm_reserve_intf(
struct dpu_rm *rm,
- struct dpu_rm_rsvp *rsvp,
+ uint32_t enc_id,
uint32_t id,
enum dpu_hw_blk_type type)
{
@@ -614,14 +501,13 @@ static int _dpu_rm_reserve_intf(
if (iter.blk->id != id)
continue;
- if (RESERVED_BY_OTHER(iter.blk, rsvp)) {
+ if (RESERVED_BY_OTHER(iter.blk, enc_id)) {
DPU_ERROR("type %d id %d already reserved\n", type, id);
return -ENAVAIL;
}
- iter.blk->rsvp_nxt = rsvp;
- trace_dpu_rm_reserve_intf(iter.blk->id, iter.blk->type,
- rsvp->enc_id);
+ iter.blk->enc_id = enc_id;
+ trace_dpu_rm_reserve_intf(iter.blk->id, enc_id);
break;
}
@@ -636,7 +522,7 @@ static int _dpu_rm_reserve_intf(
static int _dpu_rm_reserve_intf_related_hw(
struct dpu_rm *rm,
- struct dpu_rm_rsvp *rsvp,
+ uint32_t enc_id,
struct dpu_encoder_hw_resources *hw_res)
{
int i, ret = 0;
@@ -646,7 +532,7 @@ static int _dpu_rm_reserve_intf_related_hw(
if (hw_res->intfs[i] == INTF_MODE_NONE)
continue;
id = i + INTF_0;
- ret = _dpu_rm_reserve_intf(rm, rsvp, id,
+ ret = _dpu_rm_reserve_intf(rm, enc_id, id,
DPU_HW_BLK_INTF);
if (ret)
return ret;
@@ -655,33 +541,27 @@ static int _dpu_rm_reserve_intf_related_hw(
return ret;
}
-static int _dpu_rm_make_next_rsvp(
+static int _dpu_rm_make_reservation(
struct dpu_rm *rm,
struct drm_encoder *enc,
struct drm_crtc_state *crtc_state,
- struct dpu_rm_rsvp *rsvp,
struct dpu_rm_requirements *reqs)
{
int ret;
- /* Create reservation info, tag reserved blocks with it as we go */
- rsvp->seq = ++rm->rsvp_next_seq;
- rsvp->enc_id = enc->base.id;
- list_add_tail(&rsvp->list, &rm->rsvps);
-
- ret = _dpu_rm_reserve_lms(rm, rsvp, reqs);
+ ret = _dpu_rm_reserve_lms(rm, enc->base.id, reqs);
if (ret) {
DPU_ERROR("unable to find appropriate mixers\n");
return ret;
}
- ret = _dpu_rm_reserve_ctls(rm, rsvp, &reqs->topology);
+ ret = _dpu_rm_reserve_ctls(rm, enc->base.id, &reqs->topology);
if (ret) {
DPU_ERROR("unable to find appropriate CTL\n");
return ret;
}
- ret = _dpu_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res);
+ ret = _dpu_rm_reserve_intf_related_hw(rm, enc->base.id, &reqs->hw_res);
if (ret)
return ret;
@@ -706,108 +586,31 @@ static int _dpu_rm_populate_requirements(
return 0;
}
-static struct dpu_rm_rsvp *_dpu_rm_get_rsvp(
- struct dpu_rm *rm,
- struct drm_encoder *enc)
+static void _dpu_rm_release_reservation(struct dpu_rm *rm, uint32_t enc_id)
{
- struct dpu_rm_rsvp *i;
-
- if (!rm || !enc) {
- DPU_ERROR("invalid params\n");
- return NULL;
- }
-
- if (list_empty(&rm->rsvps))
- return NULL;
-
- list_for_each_entry(i, &rm->rsvps, list)
- if (i->enc_id == enc->base.id)
- return i;
-
- return NULL;
-}
-
-/**
- * _dpu_rm_release_rsvp - release resources and release a reservation
- * @rm: KMS handle
- * @rsvp: RSVP pointer to release and release resources for
- */
-static void _dpu_rm_release_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp)
-{
- struct dpu_rm_rsvp *rsvp_c, *rsvp_n;
struct dpu_rm_hw_blk *blk;
enum dpu_hw_blk_type type;
- if (!rsvp)
- return;
-
- DPU_DEBUG("rel rsvp %d enc %d\n", rsvp->seq, rsvp->enc_id);
-
- list_for_each_entry_safe(rsvp_c, rsvp_n, &rm->rsvps, list) {
- if (rsvp == rsvp_c) {
- list_del(&rsvp_c->list);
- break;
- }
- }
-
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) {
- if (blk->rsvp == rsvp) {
- blk->rsvp = NULL;
- DPU_DEBUG("rel rsvp %d enc %d %d %d\n",
- rsvp->seq, rsvp->enc_id,
- blk->type, blk->id);
- }
- if (blk->rsvp_nxt == rsvp) {
- blk->rsvp_nxt = NULL;
- DPU_DEBUG("rel rsvp_nxt %d enc %d %d %d\n",
- rsvp->seq, rsvp->enc_id,
- blk->type, blk->id);
+ if (blk->enc_id == enc_id) {
+ blk->enc_id = 0;
+ DPU_DEBUG("rel enc %d %d %d\n", enc_id,
+ type, blk->id);
}
}
}
-
- kfree(rsvp);
}
void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc)
{
- struct dpu_rm_rsvp *rsvp;
-
- if (!rm || !enc) {
- DPU_ERROR("invalid params\n");
- return;
- }
-
mutex_lock(&rm->rm_lock);
- rsvp = _dpu_rm_get_rsvp(rm, enc);
- if (!rsvp) {
- DPU_ERROR("failed to find rsvp for enc %d\n", enc->base.id);
- goto end;
- }
+ _dpu_rm_release_reservation(rm, enc->base.id);
- _dpu_rm_release_rsvp(rm, rsvp);
-end:
mutex_unlock(&rm->rm_lock);
}
-static void _dpu_rm_commit_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp)
-{
- struct dpu_rm_hw_blk *blk;
- enum dpu_hw_blk_type type;
-
- /* Swap next rsvp to be the active */
- for (type = 0; type < DPU_HW_BLK_MAX; type++) {
- list_for_each_entry(blk, &rm->hw_blks[type], list) {
- if (blk->rsvp_nxt) {
- blk->rsvp = blk->rsvp_nxt;
- blk->rsvp_nxt = NULL;
- }
- }
- }
-}
-
int dpu_rm_reserve(
struct dpu_rm *rm,
struct drm_encoder *enc,
@@ -815,7 +618,6 @@ int dpu_rm_reserve(
struct msm_display_topology topology,
bool test_only)
{
- struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt;
struct dpu_rm_requirements reqs;
int ret;
@@ -828,8 +630,6 @@ int dpu_rm_reserve(
mutex_lock(&rm->rm_lock);
- _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_BEGIN);
-
ret = _dpu_rm_populate_requirements(rm, enc, crtc_state, &reqs,
topology);
if (ret) {
@@ -837,50 +637,17 @@ int dpu_rm_reserve(
goto end;
}
- /*
- * We only support one active reservation per-hw-block. But to implement
- * transactional semantics for test-only, and for allowing failure while
- * modifying your existing reservation, over the course of this
- * function we can have two reservations:
- * Current: Existing reservation
- * Next: Proposed reservation. The proposed reservation may fail, or may
- * be discarded if in test-only mode.
- * If reservation is successful, and we're not in test-only, then we
- * replace the current with the next.
- */
- rsvp_nxt = kzalloc(sizeof(*rsvp_nxt), GFP_KERNEL);
- if (!rsvp_nxt) {
- ret = -ENOMEM;
- goto end;
- }
-
- rsvp_cur = _dpu_rm_get_rsvp(rm, enc);
-
- /* Check the proposed reservation, store it in hw's "next" field */
- ret = _dpu_rm_make_next_rsvp(rm, enc, crtc_state, rsvp_nxt, &reqs);
-
- _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_AFTER_RSVPNEXT);
-
+ ret = _dpu_rm_make_reservation(rm, enc, crtc_state, &reqs);
if (ret) {
DPU_ERROR("failed to reserve hw resources: %d\n", ret);
- _dpu_rm_release_rsvp(rm, rsvp_nxt);
+ _dpu_rm_release_reservation(rm, enc->base.id);
} else if (test_only) {
- /*
- * Normally, if test_only, test the reservation and then undo
- * However, if the user requests LOCK, then keep the reservation
- * made during the atomic_check phase.
- */
- DPU_DEBUG("test_only: discard test rsvp[s%de%d]\n",
- rsvp_nxt->seq, rsvp_nxt->enc_id);
- _dpu_rm_release_rsvp(rm, rsvp_nxt);
- } else {
- _dpu_rm_release_rsvp(rm, rsvp_cur);
-
- _dpu_rm_commit_rsvp(rm, rsvp_nxt);
+ /* test_only: test the reservation and then undo */
+ DPU_DEBUG("test_only: discard test [enc: %d]\n",
+ enc->base.id);
+ _dpu_rm_release_reservation(rm, enc->base.id);
}
- _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_FINAL);
-
end:
mutex_unlock(&rm->rm_lock);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
index b8273bd23801..381611fc5877 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
@@ -22,22 +22,14 @@
/**
* struct dpu_rm - DPU dynamic hardware resource manager
- * @dev: device handle for event logging purposes
- * @rsvps: list of hardware reservations by each crtc->encoder->connector
* @hw_blks: array of lists of hardware resources present in the system, one
* list per type of hardware block
- * @hw_mdp: hardware object for mdp_top
* @lm_max_width: cached layer mixer maximum width
- * @rsvp_next_seq: sequence number for next reservation for debugging purposes
* @rm_lock: resource manager mutex
*/
struct dpu_rm {
- struct drm_device *dev;
- struct list_head rsvps;
struct list_head hw_blks[DPU_HW_BLK_MAX];
- struct dpu_hw_mdp *hw_mdp;
uint32_t lm_max_width;
- uint32_t rsvp_next_seq;
struct mutex rm_lock;
};
@@ -67,13 +59,11 @@ struct dpu_rm_hw_iter {
* @rm: DPU Resource Manager handle
* @cat: Pointer to hardware catalog
* @mmio: mapped register io address of MDP
- * @dev: device handle for event logging purposes
* @Return: 0 on Success otherwise -ERROR
*/
int dpu_rm_init(struct dpu_rm *rm,
struct dpu_mdss_cfg *cat,
- void __iomem *mmio,
- struct drm_device *dev);
+ void __iomem *mmio);
/**
* dpu_rm_destroy - Free all memory allocated by dpu_rm_init
@@ -112,14 +102,6 @@ int dpu_rm_reserve(struct dpu_rm *rm,
void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc);
/**
- * dpu_rm_get_mdp - Retrieve HW block for MDP TOP.
- * This is never reserved, and is usable by any display.
- * @rm: DPU Resource Manager handle
- * @Return: Pointer to hw block or NULL
- */
-struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm);
-
-/**
* dpu_rm_init_hw_iter - setup given iterator for new iteration over hw list
* using dpu_rm_get_hw
* @iter: iter object to initialize
@@ -144,12 +126,4 @@ void dpu_rm_init_hw_iter(
* @Return: true on match found, false on no match found
*/
bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter);
-
-/**
- * dpu_rm_check_property_topctl - validate property bitmask before it is set
- * @val: user's proposed topology control bitmask
- * @Return: 0 on success or error
- */
-int dpu_rm_check_property_topctl(uint64_t val);
-
#endif /* __DPU_RM_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index c78b521ceda1..8bb46090bd16 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -831,48 +831,42 @@ TRACE_EVENT(dpu_plane_disable,
);
DECLARE_EVENT_CLASS(dpu_rm_iter_template,
- TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
- TP_ARGS(id, type, enc_id),
+ TP_PROTO(uint32_t id, uint32_t enc_id),
+ TP_ARGS(id, enc_id),
TP_STRUCT__entry(
__field( uint32_t, id )
- __field( enum dpu_hw_blk_type, type )
__field( uint32_t, enc_id )
),
TP_fast_assign(
__entry->id = id;
- __entry->type = type;
__entry->enc_id = enc_id;
),
- TP_printk("id:%d type:%d enc_id:%u", __entry->id, __entry->type,
- __entry->enc_id)
+ TP_printk("id:%d enc_id:%u", __entry->id, __entry->enc_id)
);
DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_intf,
- TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
- TP_ARGS(id, type, enc_id)
+ TP_PROTO(uint32_t id, uint32_t enc_id),
+ TP_ARGS(id, enc_id)
);
DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_ctls,
- TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
- TP_ARGS(id, type, enc_id)
+ TP_PROTO(uint32_t id, uint32_t enc_id),
+ TP_ARGS(id, enc_id)
);
TRACE_EVENT(dpu_rm_reserve_lms,
- TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id,
- uint32_t pp_id),
- TP_ARGS(id, type, enc_id, pp_id),
+ TP_PROTO(uint32_t id, uint32_t enc_id, uint32_t pp_id),
+ TP_ARGS(id, enc_id, pp_id),
TP_STRUCT__entry(
__field( uint32_t, id )
- __field( enum dpu_hw_blk_type, type )
__field( uint32_t, enc_id )
__field( uint32_t, pp_id )
),
TP_fast_assign(
__entry->id = id;
- __entry->type = type;
__entry->enc_id = enc_id;
__entry->pp_id = pp_id;
),
- TP_printk("id:%d type:%d enc_id:%u pp_id:%u", __entry->id,
- __entry->type, __entry->enc_id, __entry->pp_id)
+ TP_printk("id:%d enc_id:%u pp_id:%u", __entry->id,
+ __entry->enc_id, __entry->pp_id)
);
TRACE_EVENT(dpu_vbif_wait_xin_halt_fail,
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
index cc32ea5f4289..0cfd4c06b610 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
@@ -16,9 +16,9 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_mode.h>
+#include <drm/drm_probe_helper.h>
#include "mdp4_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
index 48ce218b8463..caa39b4621e3 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
@@ -18,7 +18,7 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mdp4_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
index ff8f2da160c0..259d51971401 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
@@ -16,7 +16,7 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mdp4_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
index fff77a4b12c2..df6f9803a1d7 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
@@ -17,7 +17,7 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mdp4_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
index 976585d8bfd6..9bf9d6065c55 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
@@ -12,7 +12,7 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mdp5_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
index 2f95e6525589..b0cf63c4e3d7 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -19,8 +19,8 @@
#include <linux/sort.h>
#include <drm/drm_mode.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
+#include <drm/drm_probe_helper.h>
#include "mdp5_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
index d2a56e55e53d..820a62c40063 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
@@ -17,7 +17,7 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mdp5_kms.h"
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index d2cdc7b553fe..0bdd93648761 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -207,62 +207,44 @@ u32 msm_readl(const void __iomem *addr)
return val;
}
-struct vblank_event {
- struct list_head node;
+struct msm_vblank_work {
+ struct work_struct work;
int crtc_id;
bool enable;
+ struct msm_drm_private *priv;
};
-static void vblank_ctrl_worker(struct kthread_work *work)
+static void vblank_ctrl_worker(struct work_struct *work)
{
- struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
- struct msm_vblank_ctrl, work);
- struct msm_drm_private *priv = container_of(vbl_ctrl,
- struct msm_drm_private, vblank_ctrl);
+ struct msm_vblank_work *vbl_work = container_of(work,
+ struct msm_vblank_work, work);
+ struct msm_drm_private *priv = vbl_work->priv;
struct msm_kms *kms = priv->kms;
- struct vblank_event *vbl_ev, *tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&vbl_ctrl->lock, flags);
- list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
- list_del(&vbl_ev->node);
- spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
-
- if (vbl_ev->enable)
- kms->funcs->enable_vblank(kms,
- priv->crtcs[vbl_ev->crtc_id]);
- else
- kms->funcs->disable_vblank(kms,
- priv->crtcs[vbl_ev->crtc_id]);
-
- kfree(vbl_ev);
- spin_lock_irqsave(&vbl_ctrl->lock, flags);
- }
+ if (vbl_work->enable)
+ kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]);
+ else
+ kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]);
- spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+ kfree(vbl_work);
}
static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
int crtc_id, bool enable)
{
- struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
- struct vblank_event *vbl_ev;
- unsigned long flags;
+ struct msm_vblank_work *vbl_work;
- vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC);
- if (!vbl_ev)
+ vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC);
+ if (!vbl_work)
return -ENOMEM;
- vbl_ev->crtc_id = crtc_id;
- vbl_ev->enable = enable;
+ INIT_WORK(&vbl_work->work, vblank_ctrl_worker);
- spin_lock_irqsave(&vbl_ctrl->lock, flags);
- list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
- spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+ vbl_work->crtc_id = crtc_id;
+ vbl_work->enable = enable;
+ vbl_work->priv = priv;
- kthread_queue_work(&priv->disp_thread[crtc_id].worker,
- &vbl_ctrl->work);
+ queue_work(priv->wq, &vbl_work->work);
return 0;
}
@@ -274,31 +256,20 @@ static int msm_drm_uninit(struct device *dev)
struct msm_drm_private *priv = ddev->dev_private;
struct msm_kms *kms = priv->kms;
struct msm_mdss *mdss = priv->mdss;
- struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
- struct vblank_event *vbl_ev, *tmp;
int i;
/* We must cancel and cleanup any pending vblank enable/disable
* work before drm_irq_uninstall() to avoid work re-enabling an
* irq after uninstall has disabled it.
*/
- kthread_flush_work(&vbl_ctrl->work);
- list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
- list_del(&vbl_ev->node);
- kfree(vbl_ev);
- }
- /* clean up display commit/event worker threads */
- for (i = 0; i < priv->num_crtcs; i++) {
- if (priv->disp_thread[i].thread) {
- kthread_flush_worker(&priv->disp_thread[i].worker);
- kthread_stop(priv->disp_thread[i].thread);
- priv->disp_thread[i].thread = NULL;
- }
+ flush_workqueue(priv->wq);
+ destroy_workqueue(priv->wq);
+ /* clean up event worker threads */
+ for (i = 0; i < priv->num_crtcs; i++) {
if (priv->event_thread[i].thread) {
- kthread_flush_worker(&priv->event_thread[i].worker);
- kthread_stop(priv->event_thread[i].thread);
+ kthread_destroy_worker(&priv->event_thread[i].worker);
priv->event_thread[i].thread = NULL;
}
}
@@ -323,9 +294,6 @@ static int msm_drm_uninit(struct device *dev)
drm_irq_uninstall(ddev);
pm_runtime_put_sync(dev);
- flush_workqueue(priv->wq);
- destroy_workqueue(priv->wq);
-
if (kms && kms->funcs)
kms->funcs->destroy(kms);
@@ -490,9 +458,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
priv->wq = alloc_ordered_workqueue("msm", 0);
INIT_LIST_HEAD(&priv->inactive_list);
- INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
- kthread_init_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
- spin_lock_init(&priv->vblank_ctrl.lock);
drm_mode_config_init(ddev);
@@ -554,27 +519,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
*/
param.sched_priority = 16;
for (i = 0; i < priv->num_crtcs; i++) {
-
- /* initialize display thread */
- priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id;
- kthread_init_worker(&priv->disp_thread[i].worker);
- priv->disp_thread[i].dev = ddev;
- priv->disp_thread[i].thread =
- kthread_run(kthread_worker_fn,
- &priv->disp_thread[i].worker,
- "crtc_commit:%d", priv->disp_thread[i].crtc_id);
- if (IS_ERR(priv->disp_thread[i].thread)) {
- DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n");
- priv->disp_thread[i].thread = NULL;
- goto err_msm_uninit;
- }
-
- ret = sched_setscheduler(priv->disp_thread[i].thread,
- SCHED_FIFO, &param);
- if (ret)
- dev_warn(dev, "disp_thread set priority failed: %d\n",
- ret);
-
/* initialize event thread */
priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;
kthread_init_worker(&priv->event_thread[i].worker);
@@ -589,13 +533,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
goto err_msm_uninit;
}
- /**
- * event thread should also run at same priority as disp_thread
- * because it is handling frame_done events. A lower priority
- * event thread and higher priority disp_thread can causes
- * frame_pending counters beyond 2. This can lead to commit
- * failure at crtc commit level.
- */
ret = sched_setscheduler(priv->event_thread[i].thread,
SCHED_FIFO, &param);
if (ret)
@@ -914,8 +851,12 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
ret = -EINVAL;
break;
}
- ret = copy_from_user(msm_obj->name,
- u64_to_user_ptr(args->value), args->len);
+ if (copy_from_user(msm_obj->name, u64_to_user_ptr(args->value),
+ args->len)) {
+ msm_obj->name[0] = '\0';
+ ret = -EFAULT;
+ break;
+ }
msm_obj->name[args->len] = '\0';
for (i = 0; i < args->len; i++) {
if (!isprint(msm_obj->name[i])) {
@@ -931,8 +872,9 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
}
args->len = strlen(msm_obj->name);
if (args->value) {
- ret = copy_to_user(u64_to_user_ptr(args->value),
- msm_obj->name, args->len);
+ if (copy_to_user(u64_to_user_ptr(args->value),
+ msm_obj->name, args->len))
+ ret = -EFAULT;
}
break;
}
@@ -1063,8 +1005,7 @@ static const struct file_operations fops = {
};
static struct drm_driver msm_driver = {
- .driver_features = DRIVER_HAVE_IRQ |
- DRIVER_GEM |
+ .driver_features = DRIVER_GEM |
DRIVER_PRIME |
DRIVER_RENDER |
DRIVER_ATOMIC |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 9cd6a96c6bf2..c56dade2c1dc 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -39,8 +39,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/msm_drm.h>
#include <drm/drm_gem.h>
@@ -77,12 +77,6 @@ enum msm_mdp_plane_property {
PLANE_PROP_MAX_NUM
};
-struct msm_vblank_ctrl {
- struct kthread_work work;
- struct list_head event_list;
- spinlock_t lock;
-};
-
#define MSM_GPU_MAX_RINGS 4
#define MAX_H_TILES_PER_DISPLAY 2
@@ -126,7 +120,7 @@ struct msm_display_topology {
/**
* struct msm_display_info - defines display properties
- * @intf_type: DRM_MODE_CONNECTOR_ display type
+ * @intf_type: DRM_MODE_ENCODER_ type
* @capabilities: Bitmask of display flags
* @num_of_h_tiles: Number of horizontal tiles in case of split interface
* @h_tile_instance: Controller instance used per tile. Number of elements is
@@ -199,7 +193,6 @@ struct msm_drm_private {
unsigned int num_crtcs;
struct drm_crtc *crtcs[MAX_CRTCS];
- struct msm_drm_thread disp_thread[MAX_CRTCS];
struct msm_drm_thread event_thread[MAX_CRTCS];
unsigned int num_encoders;
@@ -228,7 +221,6 @@ struct msm_drm_private {
struct notifier_block vmap_notifier;
struct shrinker shrinker;
- struct msm_vblank_ctrl vblank_ctrl;
struct drm_atomic_state *pm_state;
};
@@ -250,7 +242,8 @@ void msm_gem_purge_vma(struct msm_gem_address_space *aspace,
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma);
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, int npages);
+ struct msm_gem_vma *vma, int prot,
+ struct sg_table *sgt, int npages);
void msm_gem_close_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma);
@@ -333,6 +326,7 @@ void msm_gem_kernel_put(struct drm_gem_object *bo,
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct dma_buf *dmabuf, struct sg_table *sgt);
+__printf(2, 3)
void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);
int msm_framebuffer_prepare(struct drm_framebuffer *fb,
@@ -396,12 +390,14 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
int msm_debugfs_late_init(struct drm_device *dev);
int msm_rd_debugfs_init(struct drm_minor *minor);
void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);
+__printf(3, 4)
void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
const char *fmt, ...);
int msm_perf_debugfs_init(struct drm_minor *minor);
void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);
#else
static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }
+__printf(3, 4)
static inline void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
const char *fmt, ...) {}
static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {}
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 67dfd8d3dc12..136058978e0f 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -16,8 +16,8 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "msm_drv.h"
#include "msm_kms.h"
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 20c979a7fc9c..18ca651ab942 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -391,6 +391,10 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj,
struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct msm_gem_vma *vma;
struct page **pages;
+ int prot = IOMMU_READ;
+
+ if (!(msm_obj->flags & MSM_BO_GPU_READONLY))
+ prot |= IOMMU_WRITE;
WARN_ON(!mutex_is_locked(&msm_obj->lock));
@@ -405,8 +409,8 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj,
if (IS_ERR(pages))
return PTR_ERR(pages);
- return msm_gem_map_vma(aspace, vma, msm_obj->sgt,
- obj->size >> PAGE_SHIFT);
+ return msm_gem_map_vma(aspace, vma, prot,
+ msm_obj->sgt, obj->size >> PAGE_SHIFT);
}
/* get iova and pin it. Should have a matching put */
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 557360788084..49c04829cf34 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -68,7 +68,8 @@ void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
int
msm_gem_map_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, int npages)
+ struct msm_gem_vma *vma, int prot,
+ struct sg_table *sgt, int npages)
{
unsigned size = npages << PAGE_SHIFT;
int ret = 0;
@@ -86,7 +87,7 @@ msm_gem_map_vma(struct msm_gem_address_space *aspace,
if (aspace->mmu)
ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
- size, IOMMU_READ | IOMMU_WRITE);
+ size, prot);
if (ret)
vma->mapped = false;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 5f3eff304355..10babd18e286 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -900,7 +900,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
}
/* Get Interrupt: */
- gpu->irq = platform_get_irq_byname(pdev, config->irqname);
+ gpu->irq = platform_get_irq(pdev, 0);
if (gpu->irq < 0) {
ret = gpu->irq;
DRM_DEV_ERROR(drm->dev, "failed to get irq: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index efb49bb64191..ca17086f72c9 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -31,7 +31,6 @@ struct msm_gpu_state;
struct msm_gpu_config {
const char *ioname;
- const char *irqname;
uint64_t va_start;
uint64_t va_end;
unsigned int nr_rings;
@@ -63,7 +62,7 @@ struct msm_gpu_funcs {
struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu);
void (*recover)(struct msm_gpu *gpu);
void (*destroy)(struct msm_gpu *gpu);
-#ifdef CONFIG_DEBUG_FS
+#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
/* show GPU status in debugfs: */
void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state,
struct drm_printer *p);
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index 90e9d0a48dc0..d21172933d92 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -115,7 +115,9 @@ static void rd_write(struct msm_rd_state *rd, const void *buf, int sz)
char *fptr = &fifo->buf[fifo->head];
int n;
- wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0);
+ wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0 || !rd->open);
+ if (!rd->open)
+ return;
/* Note that smp_load_acquire() is not strictly required
* as CIRC_SPACE_TO_END() does not access the tail more
@@ -213,7 +215,10 @@ out:
static int rd_release(struct inode *inode, struct file *file)
{
struct msm_rd_state *rd = inode->i_private;
+
rd->open = false;
+ wake_up_all(&rd->fifo_event);
+
return 0;
}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
index 24b1f0c1432e..0ee1ca8a316a 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
@@ -19,12 +19,12 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 13e778825098..967379f3f571 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -31,13 +31,13 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "mxsfb_drv.h"
@@ -322,8 +322,7 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver mxsfb_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET |
- DRIVER_PRIME | DRIVER_ATOMIC |
- DRIVER_HAVE_IRQ,
+ DRIVER_PRIME | DRIVER_ATOMIC,
.irq_handler = mxsfb_irq_handler,
.irq_preinstall = mxsfb_irq_preinstall,
.irq_uninstall = mxsfb_irq_preinstall,
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
index e5edf016a439..27add9976931 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_out.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c
@@ -16,12 +16,12 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drmP.h>
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
index b17843dd050d..581404e6544d 100644
--- a/drivers/gpu/drm/nouveau/Kbuild
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -30,6 +30,8 @@ nouveau-y += nouveau_vga.o
# DRM - memory management
nouveau-y += nouveau_bo.o
nouveau-y += nouveau_gem.o
+nouveau-$(CONFIG_DRM_NOUVEAU_SVM) += nouveau_svm.o
+nouveau-$(CONFIG_DRM_NOUVEAU_SVM) += nouveau_dmem.o
nouveau-y += nouveau_mem.o
nouveau-y += nouveau_prime.o
nouveau-y += nouveau_sgdma.o
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 432c440223bb..00cd9ab8948d 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -71,3 +71,15 @@ config DRM_NOUVEAU_BACKLIGHT
help
Say Y here if you want to control the backlight of your display
(e.g. a laptop panel).
+
+config DRM_NOUVEAU_SVM
+ bool "(EXPERIMENTAL) Enable SVM (Shared Virtual Memory) support"
+ depends on ARCH_HAS_HMM
+ depends on DRM_NOUVEAU
+ depends on STAGING
+ select HMM_MIRROR
+ select DEVICE_PRIVATE
+ default n
+ help
+ Say Y here if you want to enable experimental support for
+ Shared Virtual Memory (SVM).
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 2c569e264df3..f22f01020625 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -40,6 +40,7 @@
#include "nvreg.h"
#include "nouveau_fbcon.h"
#include "disp.h"
+#include "nouveau_dma.h"
#include <subdev/bios/pll.h>
#include <subdev/clk.h>
@@ -1077,12 +1078,223 @@ nouveau_crtc_set_config(struct drm_mode_set *set,
return ret;
}
+struct nv04_page_flip_state {
+ struct list_head head;
+ struct drm_pending_vblank_event *event;
+ struct drm_crtc *crtc;
+ int bpp, pitch;
+ u64 offset;
+};
+
+static int
+nv04_finish_page_flip(struct nouveau_channel *chan,
+ struct nv04_page_flip_state *ps)
+{
+ struct nouveau_fence_chan *fctx = chan->fence;
+ struct nouveau_drm *drm = chan->drm;
+ struct drm_device *dev = drm->dev;
+ struct nv04_page_flip_state *s;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ if (list_empty(&fctx->flip)) {
+ NV_ERROR(drm, "unexpected pageflip\n");
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return -EINVAL;
+ }
+
+ s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head);
+ if (s->event) {
+ drm_crtc_arm_vblank_event(s->crtc, s->event);
+ } else {
+ /* Give up ownership of vblank for page-flipped crtc */
+ drm_crtc_vblank_put(s->crtc);
+ }
+
+ list_del(&s->head);
+ if (ps)
+ *ps = *s;
+ kfree(s);
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return 0;
+}
+
+int
+nv04_flip_complete(struct nvif_notify *notify)
+{
+ struct nouveau_cli *cli = (void *)notify->object->client;
+ struct nouveau_drm *drm = cli->drm;
+ struct nouveau_channel *chan = drm->channel;
+ struct nv04_page_flip_state state;
+
+ if (!nv04_finish_page_flip(chan, &state)) {
+ nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc),
+ state.offset + state.crtc->y *
+ state.pitch + state.crtc->x *
+ state.bpp / 8);
+ }
+
+ return NVIF_NOTIFY_KEEP;
+}
+
+static int
+nv04_page_flip_emit(struct nouveau_channel *chan,
+ struct nouveau_bo *old_bo,
+ struct nouveau_bo *new_bo,
+ struct nv04_page_flip_state *s,
+ struct nouveau_fence **pfence)
+{
+ struct nouveau_fence_chan *fctx = chan->fence;
+ struct nouveau_drm *drm = chan->drm;
+ struct drm_device *dev = drm->dev;
+ unsigned long flags;
+ int ret;
+
+ /* Queue it to the pending list */
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_add_tail(&s->head, &fctx->flip);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ /* Synchronize with the old framebuffer */
+ ret = nouveau_fence_sync(old_bo, chan, false, false);
+ if (ret)
+ goto fail;
+
+ /* Emit the pageflip */
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ goto fail;
+
+ BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
+ OUT_RING (chan, 0x00000000);
+ FIRE_RING (chan);
+
+ ret = nouveau_fence_new(chan, false, pfence);
+ if (ret)
+ goto fail;
+
+ return 0;
+fail:
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_del(&s->head);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return ret;
+}
+
+static int
+nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event, u32 flags,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
+ struct drm_device *dev = crtc->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
+ struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
+ struct nv04_page_flip_state *s;
+ struct nouveau_channel *chan;
+ struct nouveau_cli *cli;
+ struct nouveau_fence *fence;
+ struct nv04_display *dispnv04 = nv04_display(dev);
+ int head = nouveau_crtc(crtc)->index;
+ int ret;
+
+ chan = drm->channel;
+ if (!chan)
+ return -ENODEV;
+ cli = (void *)chan->user.client;
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ if (new_bo != old_bo) {
+ ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
+ if (ret)
+ goto fail_free;
+ }
+
+ mutex_lock(&cli->mutex);
+ ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL);
+ if (ret)
+ goto fail_unpin;
+
+ /* synchronise rendering channel with the kernel's channel */
+ ret = nouveau_fence_sync(new_bo, chan, false, true);
+ if (ret) {
+ ttm_bo_unreserve(&new_bo->bo);
+ goto fail_unpin;
+ }
+
+ if (new_bo != old_bo) {
+ ttm_bo_unreserve(&new_bo->bo);
+
+ ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL);
+ if (ret)
+ goto fail_unpin;
+ }
+
+ /* Initialize a page flip struct */
+ *s = (struct nv04_page_flip_state)
+ { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0],
+ new_bo->bo.offset };
+
+ /* Keep vblanks on during flip, for the target crtc of this flip */
+ drm_crtc_vblank_get(crtc);
+
+ /* Emit a page flip */
+ if (swap_interval) {
+ ret = RING_SPACE(chan, 8);
+ if (ret)
+ goto fail_unreserve;
+
+ BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1);
+ OUT_RING (chan, 0);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1);
+ OUT_RING (chan, head);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1);
+ OUT_RING (chan, 0);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1);
+ OUT_RING (chan, 0);
+ }
+
+ nouveau_bo_ref(new_bo, &dispnv04->image[head]);
+
+ ret = nv04_page_flip_emit(chan, old_bo, new_bo, s, &fence);
+ if (ret)
+ goto fail_unreserve;
+ mutex_unlock(&cli->mutex);
+
+ /* Update the crtc struct and cleanup */
+ crtc->primary->fb = fb;
+
+ nouveau_bo_fence(old_bo, fence, false);
+ ttm_bo_unreserve(&old_bo->bo);
+ if (old_bo != new_bo)
+ nouveau_bo_unpin(old_bo);
+ nouveau_fence_unref(&fence);
+ return 0;
+
+fail_unreserve:
+ drm_crtc_vblank_put(crtc);
+ ttm_bo_unreserve(&old_bo->bo);
+fail_unpin:
+ mutex_unlock(&cli->mutex);
+ if (old_bo != new_bo)
+ nouveau_bo_unpin(new_bo);
+fail_free:
+ kfree(s);
+ return ret;
+}
+
static const struct drm_crtc_funcs nv04_crtc_funcs = {
.cursor_set = nv04_crtc_cursor_set,
.cursor_move = nv04_crtc_cursor_move,
.gamma_set = nv_crtc_gamma_set,
.set_config = nouveau_crtc_set_config,
- .page_flip = nouveau_crtc_page_flip,
+ .page_flip = nv04_crtc_page_flip,
.destroy = nv_crtc_destroy,
};
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c
index 1727d399833c..5713bacaee80 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -30,6 +30,160 @@
#include "hw.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
+#include "nouveau_bo.h"
+
+#include <nvif/if0004.h>
+
+static void
+nv04_display_fini(struct drm_device *dev, bool suspend)
+{
+ struct nv04_display *disp = nv04_display(dev);
+ struct drm_crtc *crtc;
+
+ /* Disable flip completion events. */
+ nvif_notify_put(&disp->flip);
+
+ /* Disable vblank interrupts. */
+ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
+ if (nv_two_heads(dev))
+ NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
+
+ if (!suspend)
+ return;
+
+ /* Un-pin FB and cursors so they'll be evicted to system memory. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_framebuffer *nouveau_fb;
+
+ nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
+ if (!nouveau_fb || !nouveau_fb->nvbo)
+ continue;
+
+ nouveau_bo_unpin(nouveau_fb->nvbo);
+ }
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ if (nv_crtc->cursor.nvbo) {
+ if (nv_crtc->cursor.set_offset)
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+ nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+ }
+ }
+}
+
+static int
+nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
+{
+ struct nv04_display *disp = nv04_display(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_encoder *encoder;
+ struct drm_crtc *crtc;
+ int ret;
+
+ /* meh.. modeset apparently doesn't setup all the regs and depends
+ * on pre-existing state, for now load the state of the card *before*
+ * nouveau was loaded, and then do a modeset.
+ *
+ * best thing to do probably is to make save/restore routines not
+ * save/restore "pre-load" state, but more general so we can save
+ * on suspend too.
+ */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ nv_crtc->save(&nv_crtc->base);
+ }
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
+ encoder->enc_save(&encoder->base.base);
+
+ /* Enable flip completion events. */
+ nvif_notify_get(&disp->flip);
+
+ if (!resume)
+ return 0;
+
+ /* Re-pin FB/cursors. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_framebuffer *nouveau_fb;
+
+ nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
+ if (!nouveau_fb || !nouveau_fb->nvbo)
+ continue;
+
+ ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM, true);
+ if (ret)
+ NV_ERROR(drm, "Could not pin framebuffer\n");
+ }
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ if (!nv_crtc->cursor.nvbo)
+ continue;
+
+ ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
+ if (!ret && nv_crtc->cursor.set_offset)
+ ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
+ if (ret)
+ NV_ERROR(drm, "Could not pin/map cursor.\n");
+ }
+
+ /* Force CLUT to get re-loaded during modeset. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ nv_crtc->lut.depth = 0;
+ }
+
+ /* This should ensure we don't hit a locking problem when someone
+ * wakes us up via a connector. We should never go into suspend
+ * while the display is on anyways.
+ */
+ if (runtime)
+ return 0;
+
+ /* Restore mode. */
+ drm_helper_resume_force_mode(dev);
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ if (!nv_crtc->cursor.nvbo)
+ continue;
+
+ if (nv_crtc->cursor.set_offset)
+ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
+ nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
+ nv_crtc->cursor_saved_y);
+ }
+
+ return 0;
+}
+
+static void
+nv04_display_destroy(struct drm_device *dev)
+{
+ struct nv04_display *disp = nv04_display(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_encoder *encoder;
+ struct nouveau_crtc *nv_crtc;
+
+ /* Restore state */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
+ encoder->enc_restore(&encoder->base.base);
+
+ list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head)
+ nv_crtc->restore(&nv_crtc->base);
+
+ nouveau_hw_save_vga_fonts(dev, 0);
+
+ nvif_notify_fini(&disp->flip);
+
+ nouveau_display(dev)->priv = NULL;
+ kfree(disp);
+
+ nvif_object_unmap(&drm->client.device.object);
+}
int
nv04_display_create(struct drm_device *dev)
@@ -58,6 +212,13 @@ nv04_display_create(struct drm_device *dev)
/* Pre-nv50 doesn't support atomic, so don't expose the ioctls */
dev->driver->driver_features &= ~DRIVER_ATOMIC;
+ /* Request page flip completion event. */
+ if (drm->nvsw.client) {
+ nvif_notify_init(&drm->nvsw, nv04_flip_complete,
+ false, NV04_NVSW_NTFY_UEVENT,
+ NULL, 0, 0, &disp->flip);
+ }
+
nouveau_hw_save_vga_fonts(dev, 1);
nv04_crtc_create(dev, 0);
@@ -121,58 +282,3 @@ nv04_display_create(struct drm_device *dev)
return 0;
}
-
-void
-nv04_display_destroy(struct drm_device *dev)
-{
- struct nv04_display *disp = nv04_display(dev);
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_encoder *encoder;
- struct nouveau_crtc *nv_crtc;
-
- /* Restore state */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
- encoder->enc_restore(&encoder->base.base);
-
- list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head)
- nv_crtc->restore(&nv_crtc->base);
-
- nouveau_hw_save_vga_fonts(dev, 0);
-
- nouveau_display(dev)->priv = NULL;
- kfree(disp);
-
- nvif_object_unmap(&drm->client.device.object);
-}
-
-int
-nv04_display_init(struct drm_device *dev)
-{
- struct nouveau_encoder *encoder;
- struct nouveau_crtc *crtc;
-
- /* meh.. modeset apparently doesn't setup all the regs and depends
- * on pre-existing state, for now load the state of the card *before*
- * nouveau was loaded, and then do a modeset.
- *
- * best thing to do probably is to make save/restore routines not
- * save/restore "pre-load" state, but more general so we can save
- * on suspend too.
- */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
- crtc->save(&crtc->base);
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
- encoder->enc_save(&encoder->base.base);
-
- return 0;
-}
-
-void
-nv04_display_fini(struct drm_device *dev)
-{
- /* disable vblank interrupts */
- NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
- if (nv_two_heads(dev))
- NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
-}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index f74f1f2b186e..c6ed20a09f4a 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -82,6 +82,7 @@ struct nv04_display {
uint32_t saved_vga_font[4][16384];
uint32_t dac_users[4];
struct nouveau_bo *image[2];
+ struct nvif_notify flip;
};
static inline struct nv04_display *
@@ -92,9 +93,6 @@ nv04_display(struct drm_device *dev)
/* nv04_display.c */
int nv04_display_create(struct drm_device *);
-void nv04_display_destroy(struct drm_device *);
-int nv04_display_init(struct drm_device *);
-void nv04_display_fini(struct drm_device *);
/* nv04_crtc.c */
int nv04_crtc_create(struct drm_device *, int index);
@@ -176,4 +174,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
);
}
+int nv04_flip_complete(struct nvif_notify *);
#endif
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index 8fd8124d72ba..26fd71c06626 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -26,6 +26,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "nouveau_drv.h"
#include "nouveau_reg.h"
#include "nouveau_encoder.h"
diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h
index a194990d2b0d..b5fae5ab3fa8 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -116,6 +116,12 @@ struct nv50_head_atom {
u8 depth:4;
} or;
+ /* Currently only used for MST */
+ struct {
+ int pbn;
+ u8 tu:6;
+ } dp;
+
union nv50_head_atom_mask {
struct {
bool olut:1;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.c b/drivers/gpu/drm/nouveau/dispnv50/core.c
index c25e0ebe3c92..27ea3f34706d 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core.c
@@ -42,7 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore)
int version;
int (*new)(struct nouveau_drm *, s32, struct nv50_core **);
} cores[] = {
- { TU104_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
+ { TU102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
{ GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new },
{ GP102_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
{ GP100_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs.c b/drivers/gpu/drm/nouveau/dispnv50/curs.c
index cb6e4d2b1b45..121c24a18f11 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/curs.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs.c
@@ -31,7 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
int version;
int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
} curses[] = {
- { TU104_DISP_CURSOR, 0, cursc37a_new },
+ { TU102_DISP_CURSOR, 0, cursc37a_new },
{ GV100_DISP_CURSOR, 0, cursc37a_new },
{ GK104_DISP_CURSOR, 0, curs907a_new },
{ GF110_DISP_CURSOR, 0, curs907a_new },
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 67107f0b1299..4b1650f51955 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -32,10 +32,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_scdc_helper.h>
#include <drm/drm_edid.h>
@@ -659,8 +659,6 @@ struct nv50_mstc {
struct drm_display_mode *native;
struct edid *edid;
-
- int pbn;
};
struct nv50_msto {
@@ -765,18 +763,26 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
struct drm_connector *connector = conn_state->connector;
struct nv50_mstc *mstc = nv50_mstc(connector);
struct nv50_mstm *mstm = mstc->mstm;
- int bpp = connector->display_info.bpc * 3;
+ struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
int slots;
- mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock,
- bpp);
+ /* When restoring duplicated states, we need to make sure that the
+ * bw remains the same and avoid recalculating it, as the connector's
+ * bpc may have changed after the state was duplicated
+ */
+ if (!state->duplicated)
+ asyh->dp.pbn =
+ drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock,
+ connector->display_info.bpc * 3);
- if (drm_atomic_crtc_needs_modeset(crtc_state) &&
- !drm_connector_is_unregistered(connector)) {
+ if (drm_atomic_crtc_needs_modeset(crtc_state)) {
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr,
- mstc->port, mstc->pbn);
+ mstc->port,
+ asyh->dp.pbn);
if (slots < 0)
return slots;
+
+ asyh->dp.tu = slots;
}
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
@@ -787,13 +793,13 @@ static void
nv50_msto_enable(struct drm_encoder *encoder)
{
struct nv50_head *head = nv50_head(encoder->crtc);
+ struct nv50_head_atom *armh = nv50_head_atom(head->base.base.state);
struct nv50_msto *msto = nv50_msto(encoder);
struct nv50_mstc *mstc = NULL;
struct nv50_mstm *mstm = NULL;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
u8 proto, depth;
- int slots;
bool r;
drm_connector_list_iter_begin(encoder->dev, &conn_iter);
@@ -809,9 +815,10 @@ nv50_msto_enable(struct drm_encoder *encoder)
if (WARN_ON(!mstc))
return;
- slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn);
- r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots);
- WARN_ON(!r);
+ r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, armh->dp.pbn,
+ armh->dp.tu);
+ if (!r)
+ DRM_DEBUG_KMS("Failed to allocate VCPI\n");
if (!mstm->links++)
nv50_outp_acquire(mstm->outp);
@@ -828,8 +835,7 @@ nv50_msto_enable(struct drm_encoder *encoder)
default: depth = 0x6; break;
}
- mstm->outp->update(mstm->outp, head->base.index,
- nv50_head_atom(head->base.base.state), proto, depth);
+ mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth);
msto->head = head;
msto->mstc = mstc;
@@ -2215,8 +2221,8 @@ nv50_disp_func = {
* Init
*****************************************************************************/
-void
-nv50_display_fini(struct drm_device *dev)
+static void
+nv50_display_fini(struct drm_device *dev, bool suspend)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
@@ -2237,8 +2243,8 @@ nv50_display_fini(struct drm_device *dev)
}
}
-int
-nv50_display_init(struct drm_device *dev)
+static int
+nv50_display_init(struct drm_device *dev, bool resume, bool runtime)
{
struct nv50_core *core = nv50_disp(dev)->core;
struct drm_encoder *encoder;
@@ -2264,7 +2270,7 @@ nv50_display_init(struct drm_device *dev)
return 0;
}
-void
+static void
nv50_display_destroy(struct drm_device *dev)
{
struct nv50_disp *disp = nv50_disp(dev);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index ac97ebce5b35..2e7a0c347ddb 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -413,6 +413,7 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc)
asyh->ovly = armh->ovly;
asyh->dither = armh->dither;
asyh->procamp = armh->procamp;
+ asyh->dp = armh->dp;
asyh->clr.mask = 0;
asyh->set.mask = 0;
return &asyh->state;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wimm.c b/drivers/gpu/drm/nouveau/dispnv50/wimm.c
index bc9eeaf212ae..a1ac153d5e98 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wimm.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wimm.c
@@ -31,7 +31,7 @@ nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw)
int version;
int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *);
} wimms[] = {
- { TU104_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
+ { TU102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
{ GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
{}
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index ba9eea2ff16b..b95181027b31 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -626,7 +626,7 @@ nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
int (*new)(struct nouveau_drm *, enum drm_plane_type,
int, s32, struct nv50_wndw **);
} wndws[] = {
- { TU104_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new },
+ { TU102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new },
{ GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new },
{}
};
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
index 1d82cbf70cf4..7d556a1c92fa 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -54,6 +54,9 @@
#define VOLTA_USERMODE_A 0x0000c361
+#define MAXWELL_FAULT_BUFFER_A /* clb069.h */ 0x0000b069
+#define VOLTA_FAULT_BUFFER_A /* clb069.h */ 0x0000c369
+
#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b
#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e
#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e
@@ -84,7 +87,7 @@
#define GP100_DISP /* cl5070.h */ 0x00009770
#define GP102_DISP /* cl5070.h */ 0x00009870
#define GV100_DISP /* cl5070.h */ 0x0000c370
-#define TU104_DISP /* cl5070.h */ 0x0000c570
+#define TU102_DISP /* cl5070.h */ 0x0000c570
#define NV31_MPEG 0x00003174
#define G82_MPEG 0x00008274
@@ -97,7 +100,7 @@
#define GF110_DISP_CURSOR /* cl507a.h */ 0x0000907a
#define GK104_DISP_CURSOR /* cl507a.h */ 0x0000917a
#define GV100_DISP_CURSOR /* cl507a.h */ 0x0000c37a
-#define TU104_DISP_CURSOR /* cl507a.h */ 0x0000c57a
+#define TU102_DISP_CURSOR /* cl507a.h */ 0x0000c57a
#define NV50_DISP_OVERLAY /* cl507b.h */ 0x0000507b
#define G82_DISP_OVERLAY /* cl507b.h */ 0x0000827b
@@ -106,7 +109,7 @@
#define GK104_DISP_OVERLAY /* cl507b.h */ 0x0000917b
#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c37b
-#define TU104_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c57b
+#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c57b
#define NV50_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000507c
#define G82_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000827c
@@ -129,7 +132,7 @@
#define GP100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000977d
#define GP102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000987d
#define GV100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c37d
-#define TU104_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c57d
+#define TU102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c57d
#define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e
#define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e
@@ -139,7 +142,7 @@
#define GK104_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000917e
#define GV100_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c37e
-#define TU104_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c57e
+#define TU102_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c57e
#define NV50_TESLA 0x00005097
#define G82_TESLA 0x00008297
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clb069.h b/drivers/gpu/drm/nouveau/include/nvif/clb069.h
new file mode 100644
index 000000000000..eef5d0227bab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/clb069.h
@@ -0,0 +1,12 @@
+#ifndef __NVIF_CLB069_H__
+#define __NVIF_CLB069_H__
+struct nvif_clb069_v0 {
+ __u8 version;
+ __u8 pad01[3];
+ __u32 entries;
+ __u32 get;
+ __u32 put;
+};
+
+#define NVB069_V0_NTFY_FAULT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if000c.h b/drivers/gpu/drm/nouveau/include/nvif/if000c.h
index 2928ecd989ad..d6dd40f21eed 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if000c.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if000c.h
@@ -3,7 +3,8 @@
struct nvif_vmm_v0 {
__u8 version;
__u8 page_nr;
- __u8 pad02[6];
+ __u8 managed;
+ __u8 pad03[5];
__u64 addr;
__u64 size;
__u8 data[];
@@ -14,6 +15,9 @@ struct nvif_vmm_v0 {
#define NVIF_VMM_V0_PUT 0x02
#define NVIF_VMM_V0_MAP 0x03
#define NVIF_VMM_V0_UNMAP 0x04
+#define NVIF_VMM_V0_PFNMAP 0x05
+#define NVIF_VMM_V0_PFNCLR 0x06
+#define NVIF_VMM_V0_MTHD(i) ((i) + 0x80)
struct nvif_vmm_page_v0 {
__u8 version;
@@ -61,4 +65,28 @@ struct nvif_vmm_unmap_v0 {
__u8 pad01[7];
__u64 addr;
};
+
+struct nvif_vmm_pfnmap_v0 {
+ __u8 version;
+ __u8 page;
+ __u8 pad02[6];
+ __u64 addr;
+ __u64 size;
+#define NVIF_VMM_PFNMAP_V0_ADDR 0xfffffffffffff000ULL
+#define NVIF_VMM_PFNMAP_V0_ADDR_SHIFT 12
+#define NVIF_VMM_PFNMAP_V0_APER 0x00000000000000f0ULL
+#define NVIF_VMM_PFNMAP_V0_HOST 0x0000000000000000ULL
+#define NVIF_VMM_PFNMAP_V0_VRAM 0x0000000000000010ULL
+#define NVIF_VMM_PFNMAP_V0_W 0x0000000000000002ULL
+#define NVIF_VMM_PFNMAP_V0_V 0x0000000000000001ULL
+#define NVIF_VMM_PFNMAP_V0_NONE 0x0000000000000000ULL
+ __u64 phys[];
+};
+
+struct nvif_vmm_pfnclr_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u64 addr;
+ __u64 size;
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/ifc00d.h b/drivers/gpu/drm/nouveau/include/nvif/ifc00d.h
index 1d9c637859f3..4cabd613a280 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/ifc00d.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/ifc00d.h
@@ -6,6 +6,12 @@ struct gp100_vmm_vn {
/* nvif_vmm_vX ... */
};
+struct gp100_vmm_v0 {
+ /* nvif_vmm_vX ... */
+ __u8 version;
+ __u8 fault_replay;
+};
+
struct gp100_vmm_map_vn {
/* nvif_vmm_map_vX ... */
};
@@ -18,4 +24,19 @@ struct gp100_vmm_map_v0 {
__u8 priv;
__u8 kind;
};
+
+#define GP100_VMM_VN_FAULT_REPLAY NVIF_VMM_V0_MTHD(0x00)
+#define GP100_VMM_VN_FAULT_CANCEL NVIF_VMM_V0_MTHD(0x01)
+
+struct gp100_vmm_fault_replay_vn {
+};
+
+struct gp100_vmm_fault_cancel_v0 {
+ __u8 version;
+ __u8 hub;
+ __u8 gpc;
+ __u8 client;
+ __u8 pad04[4];
+ __u64 inst;
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/vmm.h b/drivers/gpu/drm/nouveau/include/nvif/vmm.h
index c5db8a2e82df..79bf85d2f43a 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/vmm.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/vmm.h
@@ -30,8 +30,8 @@ struct nvif_vmm {
int page_nr;
};
-int nvif_vmm_init(struct nvif_mmu *, s32 oclass, u64 addr, u64 size,
- void *argv, u32 argc, struct nvif_vmm *);
+int nvif_vmm_init(struct nvif_mmu *, s32 oclass, bool managed, u64 addr,
+ u64 size, void *argv, u32 argc, struct nvif_vmm *);
void nvif_vmm_fini(struct nvif_vmm *);
int nvif_vmm_get(struct nvif_vmm *, enum nvif_vmm_get, bool sparse,
u8 page, u8 align, u64 size, struct nvif_vma *);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
index 72e4dc1f0236..642492344196 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -28,6 +28,7 @@ enum nvkm_devidx {
NVKM_SUBDEV_ICCSENSE,
NVKM_SUBDEV_THERM,
NVKM_SUBDEV_CLK,
+ NVKM_SUBDEV_GSP,
NVKM_SUBDEV_SECBOOT,
NVKM_ENGINE_BSP,
@@ -137,6 +138,7 @@ struct nvkm_device {
struct nvkm_fb *fb;
struct nvkm_fuse *fuse;
struct nvkm_gpio *gpio;
+ struct nvkm_gsp *gsp;
struct nvkm_i2c *i2c;
struct nvkm_subdev *ibus;
struct nvkm_iccsense *iccsense;
@@ -209,6 +211,7 @@ struct nvkm_device_chip {
int (*fb )(struct nvkm_device *, int idx, struct nvkm_fb **);
int (*fuse )(struct nvkm_device *, int idx, struct nvkm_fuse **);
int (*gpio )(struct nvkm_device *, int idx, struct nvkm_gpio **);
+ int (*gsp )(struct nvkm_device *, int idx, struct nvkm_gsp **);
int (*i2c )(struct nvkm_device *, int idx, struct nvkm_i2c **);
int (*ibus )(struct nvkm_device *, int idx, struct nvkm_subdev **);
int (*iccsense)(struct nvkm_device *, int idx, struct nvkm_iccsense **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
index 86abe76023c2..5f3650692e4d 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
@@ -11,5 +11,5 @@ int gm200_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
int gp100_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
int gp102_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
int gv100_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
-int tu104_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
+int tu102_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 5ca86e178bb9..3026b22d44fb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -36,5 +36,5 @@ int gm200_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gp100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gp102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gv100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
-int tu104_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
+int tu102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
index 3b2b685778eb..b7fc04dd1628 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
@@ -74,5 +74,5 @@ int gm20b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
int gp100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
int gp10b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
int gv100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
-int tu104_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
+int tu102_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
index ba1518ff8b66..1e924c7f7ba7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
@@ -10,6 +10,9 @@ struct nvkm_gr {
u64 nvkm_gr_units(struct nvkm_gr *);
int nvkm_gr_tlb_flush(struct nvkm_gr *);
+int nvkm_gr_ctxsw_pause(struct nvkm_device *);
+int nvkm_gr_ctxsw_resume(struct nvkm_device *);
+u32 nvkm_gr_ctxsw_inst(struct nvkm_device *);
int nv04_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
int nv10_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
index fe716859d4a9..b72a4844c5f7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
@@ -6,6 +6,8 @@
struct nvkm_nvdec {
struct nvkm_engine engine;
+ u32 addr;
+
struct nvkm_falcon *falcon;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
index f7d89822b905..c93ad332461a 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
@@ -5,10 +5,13 @@
struct nvkm_sec2 {
struct nvkm_engine engine;
+ u32 addr;
+
struct nvkm_falcon *falcon;
struct nvkm_msgqueue *queue;
struct work_struct work;
};
int gp102_sec2_new(struct nvkm_device *, int, struct nvkm_sec2 **);
+int tu102_sec2_new(struct nvkm_device *, int, struct nvkm_sec2 **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
index fd9d713b611c..da14486317ca 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
@@ -29,5 +29,5 @@ int gf100_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
int gk20a_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
int gm107_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
int gm20b_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
-int tu104_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
+int tu102_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
index 1b71812a790b..8ba982c2fdfb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
@@ -31,5 +31,5 @@ int gf100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
int gm107_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
int gm200_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
int gv100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
-int tu104_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
+int tu102_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
index 127f48066026..97322f95b3ee 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
@@ -13,6 +13,8 @@ struct nvkm_fault {
struct nvkm_event event;
struct nvkm_notify nrpfb;
+
+ struct nvkm_device_oclass user;
};
struct nvkm_fault_data {
@@ -30,5 +32,5 @@ struct nvkm_fault_data {
int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
int gv100_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
-int tu104_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
+int tu102_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
new file mode 100644
index 000000000000..4c672a5c4cd5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
@@ -0,0 +1,14 @@
+#ifndef __NVKM_GSP_H__
+#define __NVKM_GSP_H__
+#define nvkm_gsp(p) container_of((p), struct nvkm_gsp, subdev)
+#include <core/subdev.h>
+
+struct nvkm_gsp {
+ struct nvkm_subdev subdev;
+ u32 addr;
+
+ struct nvkm_falcon *falcon;
+};
+
+int gv100_gsp_new(struct nvkm_device *, int, struct nvkm_gsp **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
index b66dedd8abb6..e38f4958dea2 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
@@ -31,5 +31,5 @@ int gk104_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int gp100_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int gp10b_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
-int tu104_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
+int tu102_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
index 0a0e064f22e5..28ade86f74c5 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
@@ -17,6 +17,7 @@ struct nvkm_vma {
bool part:1; /* Region was split from an allocated region by map(). */
bool user:1; /* Region user-allocated. */
bool busy:1; /* Region busy (for temporarily preventing user access). */
+ bool mapped:1; /* Region contains valid pages. */
struct nvkm_memory *memory; /* Memory currently mapped into VMA. */
struct nvkm_tags *tags; /* Compression tag reference. */
};
@@ -44,6 +45,8 @@ struct nvkm_vmm {
dma_addr_t null;
void *nullp;
+
+ bool replay;
};
int nvkm_vmm_new(struct nvkm_device *, u64 addr, u64 size, void *argv, u32 argc,
@@ -63,6 +66,7 @@ struct nvkm_vmm_map {
struct nvkm_mm_node *mem;
struct scatterlist *sgl;
dma_addr_t *dma;
+ u64 *pfn;
u64 off;
const struct nvkm_vmm_page *page;
@@ -130,5 +134,5 @@ int gm20b_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
int gp100_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
int gp10b_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
int gv100_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
-int tu104_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
+int tu102_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
index f7d3eb647e2e..2904e67d79d2 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
@@ -9,6 +9,7 @@ struct nvkm_top {
struct list_head device;
};
+u32 nvkm_top_addr(struct nvkm_device *, enum nvkm_devidx);
u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_devidx);
u32 nvkm_top_intr(struct nvkm_device *, u32 intr, u64 *subdevs);
u32 nvkm_top_intr_mask(struct nvkm_device *, enum nvkm_devidx);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
index 8a0f85f5fc1a..6a765682fbfa 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
@@ -38,6 +38,7 @@ int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
+int gf117_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index b06cdac8f3a2..c3fd5dd39ed9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -214,6 +214,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
WARN_ON(1);
break;
}
+ break;
case NOUVEAU_GETPARAM_FB_SIZE:
getparam->value = drm->gem.vram_available;
break;
@@ -338,7 +339,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
goto done;
if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
- ret = nouveau_vma_new(chan->ntfy, &cli->vmm, &chan->ntfy_vma);
+ ret = nouveau_vma_new(chan->ntfy, chan->chan->vmm,
+ &chan->ntfy_vma);
if (ret)
goto done;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 5f5be6368aed..c7a94c94dbf3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -253,6 +253,9 @@ nouveau_backlight_init(struct drm_connector *connector)
case NV_DEVICE_INFO_V0_FERMI:
case NV_DEVICE_INFO_V0_KEPLER:
case NV_DEVICE_INFO_V0_MAXWELL:
+ case NV_DEVICE_INFO_V0_PASCAL:
+ case NV_DEVICE_INFO_V0_VOLTA:
+ case NV_DEVICE_INFO_V0_TURING:
ret = nv50_backlight_init(nv_encoder, &props, &ops);
break;
default:
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 73eff52036d2..34a998012bf6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -194,7 +194,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
struct nouveau_drm *drm = cli->drm;
struct nouveau_bo *nvbo;
struct nvif_mmu *mmu = &cli->mmu;
- struct nvif_vmm *vmm = &cli->vmm.vmm;
+ struct nvif_vmm *vmm = cli->svm.cli ? &cli->svm.vmm : &cli->vmm.vmm;
size_t acc_size;
int type = ttm_bo_type_device;
int ret, i, pi = -1;
@@ -1434,7 +1434,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 || !mem->kind)
/* untiled */
break;
- /* fallthrough, tiled memory */
+ /* fall through - tiled memory */
case TTM_PL_VRAM:
reg->bus.offset = reg->start << PAGE_SHIFT;
reg->bus.base = device->func->resource_addr(device, 1);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index 73c48440d4d7..846f4bdec0de 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -61,12 +61,14 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
return -EINVAL;
prev = *pnvbo;
- *pnvbo = ref ? nouveau_bo(ttm_bo_reference(&ref->bo)) : NULL;
- if (prev) {
- struct ttm_buffer_object *bo = &prev->bo;
-
- ttm_bo_unref(&bo);
+ if (ref) {
+ ttm_bo_get(&ref->bo);
+ *pnvbo = nouveau_bo(&ref->bo);
+ } else {
+ *pnvbo = NULL;
}
+ if (prev)
+ ttm_bo_put(&prev->bo);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 668afbc29c3e..282fd90b65e1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -42,6 +42,7 @@
#include "nouveau_fence.h"
#include "nouveau_abi16.h"
#include "nouveau_vmm.h"
+#include "nouveau_svm.h"
MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
int nouveau_vram_pushbuf;
@@ -95,6 +96,10 @@ nouveau_channel_del(struct nouveau_channel **pchan)
if (chan->fence)
nouveau_fence(chan->drm)->context_del(chan);
+
+ if (cli)
+ nouveau_svmm_part(chan->vmm->svmm, chan->inst);
+
nvif_object_fini(&chan->nvsw);
nvif_object_fini(&chan->gart);
nvif_object_fini(&chan->vram);
@@ -130,6 +135,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
chan->device = device;
chan->drm = drm;
+ chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
atomic_set(&chan->killed, 0);
/* allocate memory for dma push buffer */
@@ -157,7 +163,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
chan->push.addr = chan->push.buffer->bo.offset;
if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
- ret = nouveau_vma_new(chan->push.buffer, &cli->vmm,
+ ret = nouveau_vma_new(chan->push.buffer, chan->vmm,
&chan->push.vma);
if (ret) {
nouveau_channel_del(pchan);
@@ -172,7 +178,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vmm.vmm.limit - 1;
+ args.limit = chan->vmm->vmm.limit - 1;
} else
if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
@@ -202,7 +208,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_RDWR;
args.start = 0;
- args.limit = cli->vmm.vmm.limit - 1;
+ args.limit = chan->vmm->vmm.limit - 1;
}
}
@@ -220,7 +226,6 @@ static int
nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
u64 runlist, bool priv, struct nouveau_channel **pchan)
{
- struct nouveau_cli *cli = (void *)device->object.client;
static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A,
VOLTA_CHANNEL_GPFIFO_A,
PASCAL_CHANNEL_GPFIFO_A,
@@ -255,7 +260,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
args.volta.ilength = 0x02000;
args.volta.ioffset = 0x10000 + chan->push.addr;
args.volta.runlist = runlist;
- args.volta.vmm = nvif_handle(&cli->vmm.vmm.object);
+ args.volta.vmm = nvif_handle(&chan->vmm->vmm.object);
args.volta.priv = priv;
size = sizeof(args.volta);
} else
@@ -264,7 +269,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
args.kepler.ilength = 0x02000;
args.kepler.ioffset = 0x10000 + chan->push.addr;
args.kepler.runlist = runlist;
- args.kepler.vmm = nvif_handle(&cli->vmm.vmm.object);
+ args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object);
args.kepler.priv = priv;
size = sizeof(args.kepler);
} else
@@ -272,14 +277,14 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
args.fermi.version = 0;
args.fermi.ilength = 0x02000;
args.fermi.ioffset = 0x10000 + chan->push.addr;
- args.fermi.vmm = nvif_handle(&cli->vmm.vmm.object);
+ args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object);
size = sizeof(args.fermi);
} else {
args.nv50.version = 0;
args.nv50.ilength = 0x02000;
args.nv50.ioffset = 0x10000 + chan->push.addr;
args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
- args.nv50.vmm = nvif_handle(&cli->vmm.vmm.object);
+ args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object);
size = sizeof(args.nv50);
}
@@ -350,7 +355,6 @@ static int
nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
{
struct nvif_device *device = chan->device;
- struct nouveau_cli *cli = (void *)chan->user.client;
struct nouveau_drm *drm = chan->drm;
struct nv_dma_v0 args = {};
int ret, i;
@@ -376,7 +380,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vmm.vmm.limit - 1;
+ args.limit = chan->vmm->vmm.limit - 1;
} else {
args.target = NV_DMA_V0_TARGET_VRAM;
args.access = NV_DMA_V0_ACCESS_RDWR;
@@ -393,7 +397,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vmm.vmm.limit - 1;
+ args.limit = chan->vmm->vmm.limit - 1;
} else
if (chan->drm->agp.bridge) {
args.target = NV_DMA_V0_TARGET_AGP;
@@ -405,7 +409,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_RDWR;
args.start = 0;
- args.limit = cli->vmm.vmm.limit - 1;
+ args.limit = chan->vmm->vmm.limit - 1;
}
ret = nvif_object_init(&chan->user, gart, NV_DMA_IN_MEMORY,
@@ -495,6 +499,10 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
nouveau_channel_del(pchan);
}
+ ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst);
+ if (ret)
+ nouveau_channel_del(pchan);
+
done:
cli->base.super = super;
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h
index 28418f4e5748..93814d1d31e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.h
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.h
@@ -8,6 +8,7 @@ struct nvif_device;
struct nouveau_channel {
struct nvif_device *device;
struct nouveau_drm *drm;
+ struct nouveau_vmm *vmm;
int chid;
u64 inst;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 3f463c91314a..4116ee62adaf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -33,6 +33,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_atomic.h>
#include "nouveau_reg.h"
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 5d273a655479..55c0fa451163 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -30,19 +30,15 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
-
-#include <nvif/class.h>
+#include <drm/drm_probe_helper.h>
#include "nouveau_fbcon.h"
-#include "dispnv04/hw.h"
#include "nouveau_crtc.h"
-#include "nouveau_dma.h"
#include "nouveau_gem.h"
#include "nouveau_connector.h"
#include "nv50_display.h"
-#include "nouveau_fence.h"
-
+#include <nvif/class.h>
#include <nvif/cl0046.h>
#include <nvif/event.h>
@@ -411,15 +407,14 @@ nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
#endif
int
-nouveau_display_init(struct drm_device *dev)
+nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
- struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int ret;
- ret = disp->init(dev);
+ ret = disp->init(dev, resume, runtime);
if (ret)
return ret;
@@ -436,8 +431,6 @@ nouveau_display_init(struct drm_device *dev)
}
drm_connector_list_iter_end(&conn_iter);
- /* enable flip completion events */
- nvif_notify_get(&drm->flip);
return ret;
}
@@ -456,9 +449,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
drm_helper_force_disable_all(dev);
}
- /* disable flip completion events */
- nvif_notify_put(&drm->flip);
-
/* disable hotplug interrupts */
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
@@ -471,7 +461,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
cancel_work_sync(&drm->hpd_work);
drm_kms_helper_poll_disable(dev);
- disp->fini(dev);
+ disp->fini(dev, suspend);
}
static void
@@ -624,7 +614,6 @@ int
nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
- struct drm_crtc *crtc;
if (drm_drv_uses_atomic_modeset(dev)) {
if (!runtime) {
@@ -635,32 +624,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
return ret;
}
}
-
- nouveau_display_fini(dev, true, runtime);
- return 0;
}
nouveau_display_fini(dev, true, runtime);
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_framebuffer *nouveau_fb;
-
- nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
- if (!nouveau_fb || !nouveau_fb->nvbo)
- continue;
-
- nouveau_bo_unpin(nouveau_fb->nvbo);
- }
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (nv_crtc->cursor.nvbo) {
- if (nv_crtc->cursor.set_offset)
- nouveau_bo_unmap(nv_crtc->cursor.nvbo);
- nouveau_bo_unpin(nv_crtc->cursor.nvbo);
- }
- }
-
return 0;
}
@@ -668,275 +634,16 @@ void
nouveau_display_resume(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct drm_crtc *crtc;
- int ret;
+
+ nouveau_display_init(dev, true, runtime);
if (drm_drv_uses_atomic_modeset(dev)) {
- nouveau_display_init(dev);
if (disp->suspend) {
drm_atomic_helper_resume(dev, disp->suspend);
disp->suspend = NULL;
}
return;
}
-
- /* re-pin fb/cursors */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_framebuffer *nouveau_fb;
-
- nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
- if (!nouveau_fb || !nouveau_fb->nvbo)
- continue;
-
- ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM, true);
- if (ret)
- NV_ERROR(drm, "Could not pin framebuffer\n");
- }
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (!nv_crtc->cursor.nvbo)
- continue;
-
- ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
- if (!ret && nv_crtc->cursor.set_offset)
- ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
- if (ret)
- NV_ERROR(drm, "Could not pin/map cursor.\n");
- }
-
- nouveau_display_init(dev);
-
- /* Force CLUT to get re-loaded during modeset */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
- nv_crtc->lut.depth = 0;
- }
-
- /* This should ensure we don't hit a locking problem when someone
- * wakes us up via a connector. We should never go into suspend
- * while the display is on anyways.
- */
- if (runtime)
- return;
-
- drm_helper_resume_force_mode(dev);
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
- if (!nv_crtc->cursor.nvbo)
- continue;
-
- if (nv_crtc->cursor.set_offset)
- nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
- nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
- nv_crtc->cursor_saved_y);
- }
-}
-
-static int
-nouveau_page_flip_emit(struct nouveau_channel *chan,
- struct nouveau_bo *old_bo,
- struct nouveau_bo *new_bo,
- struct nouveau_page_flip_state *s,
- struct nouveau_fence **pfence)
-{
- struct nouveau_fence_chan *fctx = chan->fence;
- struct nouveau_drm *drm = chan->drm;
- struct drm_device *dev = drm->dev;
- unsigned long flags;
- int ret;
-
- /* Queue it to the pending list */
- spin_lock_irqsave(&dev->event_lock, flags);
- list_add_tail(&s->head, &fctx->flip);
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- /* Synchronize with the old framebuffer */
- ret = nouveau_fence_sync(old_bo, chan, false, false);
- if (ret)
- goto fail;
-
- /* Emit the pageflip */
- ret = RING_SPACE(chan, 2);
- if (ret)
- goto fail;
-
- BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
- OUT_RING (chan, 0x00000000);
- FIRE_RING (chan);
-
- ret = nouveau_fence_new(chan, false, pfence);
- if (ret)
- goto fail;
-
- return 0;
-fail:
- spin_lock_irqsave(&dev->event_lock, flags);
- list_del(&s->head);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- return ret;
-}
-
-int
-nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event, u32 flags,
- struct drm_modeset_acquire_ctx *ctx)
-{
- const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
- struct drm_device *dev = crtc->dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
- struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
- struct nouveau_page_flip_state *s;
- struct nouveau_channel *chan;
- struct nouveau_cli *cli;
- struct nouveau_fence *fence;
- struct nv04_display *dispnv04 = nv04_display(dev);
- int head = nouveau_crtc(crtc)->index;
- int ret;
-
- chan = drm->channel;
- if (!chan)
- return -ENODEV;
- cli = (void *)chan->user.client;
-
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- if (new_bo != old_bo) {
- ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
- if (ret)
- goto fail_free;
- }
-
- mutex_lock(&cli->mutex);
- ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL);
- if (ret)
- goto fail_unpin;
-
- /* synchronise rendering channel with the kernel's channel */
- ret = nouveau_fence_sync(new_bo, chan, false, true);
- if (ret) {
- ttm_bo_unreserve(&new_bo->bo);
- goto fail_unpin;
- }
-
- if (new_bo != old_bo) {
- ttm_bo_unreserve(&new_bo->bo);
-
- ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL);
- if (ret)
- goto fail_unpin;
- }
-
- /* Initialize a page flip struct */
- *s = (struct nouveau_page_flip_state)
- { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0],
- new_bo->bo.offset };
-
- /* Keep vblanks on during flip, for the target crtc of this flip */
- drm_crtc_vblank_get(crtc);
-
- /* Emit a page flip */
- if (swap_interval) {
- ret = RING_SPACE(chan, 8);
- if (ret)
- goto fail_unreserve;
-
- BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1);
- OUT_RING (chan, 0);
- BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1);
- OUT_RING (chan, head);
- BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1);
- OUT_RING (chan, 0);
- BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1);
- OUT_RING (chan, 0);
- }
-
- nouveau_bo_ref(new_bo, &dispnv04->image[head]);
-
- ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
- if (ret)
- goto fail_unreserve;
- mutex_unlock(&cli->mutex);
-
- /* Update the crtc struct and cleanup */
- crtc->primary->fb = fb;
-
- nouveau_bo_fence(old_bo, fence, false);
- ttm_bo_unreserve(&old_bo->bo);
- if (old_bo != new_bo)
- nouveau_bo_unpin(old_bo);
- nouveau_fence_unref(&fence);
- return 0;
-
-fail_unreserve:
- drm_crtc_vblank_put(crtc);
- ttm_bo_unreserve(&old_bo->bo);
-fail_unpin:
- mutex_unlock(&cli->mutex);
- if (old_bo != new_bo)
- nouveau_bo_unpin(new_bo);
-fail_free:
- kfree(s);
- return ret;
-}
-
-int
-nouveau_finish_page_flip(struct nouveau_channel *chan,
- struct nouveau_page_flip_state *ps)
-{
- struct nouveau_fence_chan *fctx = chan->fence;
- struct nouveau_drm *drm = chan->drm;
- struct drm_device *dev = drm->dev;
- struct nouveau_page_flip_state *s;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->event_lock, flags);
-
- if (list_empty(&fctx->flip)) {
- NV_ERROR(drm, "unexpected pageflip\n");
- spin_unlock_irqrestore(&dev->event_lock, flags);
- return -EINVAL;
- }
-
- s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
- if (s->event) {
- drm_crtc_arm_vblank_event(s->crtc, s->event);
- } else {
- /* Give up ownership of vblank for page-flipped crtc */
- drm_crtc_vblank_put(s->crtc);
- }
-
- list_del(&s->head);
- if (ps)
- *ps = *s;
- kfree(s);
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
- return 0;
-}
-
-int
-nouveau_flip_complete(struct nvif_notify *notify)
-{
- struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip);
- struct nouveau_channel *chan = drm->channel;
- struct nouveau_page_flip_state state;
-
- if (!nouveau_finish_page_flip(chan, &state)) {
- nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc),
- state.offset + state.crtc->y *
- state.pitch + state.crtc->x *
- state.bpp / 8);
- }
-
- return NVIF_NOTIFY_KEEP;
}
int
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index eb77e41c2d4e..311e175f0513 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -25,19 +25,11 @@ int nouveau_framebuffer_new(struct drm_device *,
const struct drm_mode_fb_cmd2 *,
struct nouveau_bo *, struct nouveau_framebuffer **);
-struct nouveau_page_flip_state {
- struct list_head head;
- struct drm_pending_vblank_event *event;
- struct drm_crtc *crtc;
- int bpp, pitch;
- u64 offset;
-};
-
struct nouveau_display {
void *priv;
void (*dtor)(struct drm_device *);
- int (*init)(struct drm_device *);
- void (*fini)(struct drm_device *);
+ int (*init)(struct drm_device *, bool resume, bool runtime);
+ void (*fini)(struct drm_device *, bool suspend);
struct nvif_disp disp;
@@ -61,7 +53,7 @@ nouveau_display(struct drm_device *dev)
int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev);
-int nouveau_display_init(struct drm_device *dev);
+int nouveau_display_init(struct drm_device *dev, bool resume, bool runtime);
void nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime);
int nouveau_display_suspend(struct drm_device *dev, bool runtime);
void nouveau_display_resume(struct drm_device *dev, bool runtime);
@@ -71,13 +63,6 @@ bool nouveau_display_scanoutpos(struct drm_device *, unsigned int,
bool, int *, int *, ktime_t *,
ktime_t *, const struct drm_display_mode *);
-int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event,
- uint32_t page_flip_flags,
- struct drm_modeset_acquire_ctx *ctx);
-int nouveau_finish_page_flip(struct nouveau_channel *,
- struct nouveau_page_flip_state *);
-
int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
struct drm_mode_create_dumb *args);
int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
new file mode 100644
index 000000000000..8be7a83ced9b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nouveau_dmem.h"
+#include "nouveau_drv.h"
+#include "nouveau_chan.h"
+#include "nouveau_dma.h"
+#include "nouveau_mem.h"
+#include "nouveau_bo.h"
+
+#include <nvif/class.h>
+#include <nvif/object.h>
+#include <nvif/if500b.h>
+#include <nvif/if900b.h>
+
+#include <linux/sched/mm.h>
+#include <linux/hmm.h>
+
+/*
+ * FIXME: this is ugly right now we are using TTM to allocate vram and we pin
+ * it in vram while in use. We likely want to overhaul memory management for
+ * nouveau to be more page like (not necessarily with system page size but a
+ * bigger page size) at lowest level and have some shim layer on top that would
+ * provide the same functionality as TTM.
+ */
+#define DMEM_CHUNK_SIZE (2UL << 20)
+#define DMEM_CHUNK_NPAGES (DMEM_CHUNK_SIZE >> PAGE_SHIFT)
+
+struct nouveau_migrate;
+
+enum nouveau_aper {
+ NOUVEAU_APER_VIRT,
+ NOUVEAU_APER_VRAM,
+ NOUVEAU_APER_HOST,
+};
+
+typedef int (*nouveau_migrate_copy_t)(struct nouveau_drm *drm, u64 npages,
+ enum nouveau_aper, u64 dst_addr,
+ enum nouveau_aper, u64 src_addr);
+
+struct nouveau_dmem_chunk {
+ struct list_head list;
+ struct nouveau_bo *bo;
+ struct nouveau_drm *drm;
+ unsigned long pfn_first;
+ unsigned long callocated;
+ unsigned long bitmap[BITS_TO_LONGS(DMEM_CHUNK_NPAGES)];
+ spinlock_t lock;
+};
+
+struct nouveau_dmem_migrate {
+ nouveau_migrate_copy_t copy_func;
+ struct nouveau_channel *chan;
+};
+
+struct nouveau_dmem {
+ struct hmm_devmem *devmem;
+ struct nouveau_dmem_migrate migrate;
+ struct list_head chunk_free;
+ struct list_head chunk_full;
+ struct list_head chunk_empty;
+ struct mutex mutex;
+};
+
+struct nouveau_dmem_fault {
+ struct nouveau_drm *drm;
+ struct nouveau_fence *fence;
+ dma_addr_t *dma;
+ unsigned long npages;
+};
+
+struct nouveau_migrate {
+ struct vm_area_struct *vma;
+ struct nouveau_drm *drm;
+ struct nouveau_fence *fence;
+ unsigned long npages;
+ dma_addr_t *dma;
+ unsigned long dma_nr;
+};
+
+static void
+nouveau_dmem_free(struct hmm_devmem *devmem, struct page *page)
+{
+ struct nouveau_dmem_chunk *chunk;
+ struct nouveau_drm *drm;
+ unsigned long idx;
+
+ chunk = (void *)hmm_devmem_page_get_drvdata(page);
+ idx = page_to_pfn(page) - chunk->pfn_first;
+ drm = chunk->drm;
+
+ /*
+ * FIXME:
+ *
+ * This is really a bad example, we need to overhaul nouveau memory
+ * management to be more page focus and allow lighter locking scheme
+ * to be use in the process.
+ */
+ spin_lock(&chunk->lock);
+ clear_bit(idx, chunk->bitmap);
+ WARN_ON(!chunk->callocated);
+ chunk->callocated--;
+ /*
+ * FIXME when chunk->callocated reach 0 we should add the chunk to
+ * a reclaim list so that it can be freed in case of memory pressure.
+ */
+ spin_unlock(&chunk->lock);
+}
+
+static void
+nouveau_dmem_fault_alloc_and_copy(struct vm_area_struct *vma,
+ const unsigned long *src_pfns,
+ unsigned long *dst_pfns,
+ unsigned long start,
+ unsigned long end,
+ void *private)
+{
+ struct nouveau_dmem_fault *fault = private;
+ struct nouveau_drm *drm = fault->drm;
+ struct device *dev = drm->dev->dev;
+ unsigned long addr, i, npages = 0;
+ nouveau_migrate_copy_t copy;
+ int ret;
+
+
+ /* First allocate new memory */
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, i++) {
+ struct page *dpage, *spage;
+
+ dst_pfns[i] = 0;
+ spage = migrate_pfn_to_page(src_pfns[i]);
+ if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE))
+ continue;
+
+ dpage = hmm_vma_alloc_locked_page(vma, addr);
+ if (!dpage) {
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ continue;
+ }
+
+ dst_pfns[i] = migrate_pfn(page_to_pfn(dpage)) |
+ MIGRATE_PFN_LOCKED;
+ npages++;
+ }
+
+ /* Allocate storage for DMA addresses, so we can unmap later. */
+ fault->dma = kmalloc(sizeof(*fault->dma) * npages, GFP_KERNEL);
+ if (!fault->dma)
+ goto error;
+
+ /* Copy things over */
+ copy = drm->dmem->migrate.copy_func;
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, i++) {
+ struct nouveau_dmem_chunk *chunk;
+ struct page *spage, *dpage;
+ u64 src_addr, dst_addr;
+
+ dpage = migrate_pfn_to_page(dst_pfns[i]);
+ if (!dpage || dst_pfns[i] == MIGRATE_PFN_ERROR)
+ continue;
+
+ spage = migrate_pfn_to_page(src_pfns[i]);
+ if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE)) {
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ __free_page(dpage);
+ continue;
+ }
+
+ fault->dma[fault->npages] =
+ dma_map_page_attrs(dev, dpage, 0, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(dev, fault->dma[fault->npages])) {
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ __free_page(dpage);
+ continue;
+ }
+
+ dst_addr = fault->dma[fault->npages++];
+
+ chunk = (void *)hmm_devmem_page_get_drvdata(spage);
+ src_addr = page_to_pfn(spage) - chunk->pfn_first;
+ src_addr = (src_addr << PAGE_SHIFT) + chunk->bo->bo.offset;
+
+ ret = copy(drm, 1, NOUVEAU_APER_HOST, dst_addr,
+ NOUVEAU_APER_VRAM, src_addr);
+ if (ret) {
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ __free_page(dpage);
+ continue;
+ }
+ }
+
+ nouveau_fence_new(drm->dmem->migrate.chan, false, &fault->fence);
+
+ return;
+
+error:
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, ++i) {
+ struct page *page;
+
+ if (!dst_pfns[i] || dst_pfns[i] == MIGRATE_PFN_ERROR)
+ continue;
+
+ page = migrate_pfn_to_page(dst_pfns[i]);
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ if (page == NULL)
+ continue;
+
+ __free_page(page);
+ }
+}
+
+void nouveau_dmem_fault_finalize_and_map(struct vm_area_struct *vma,
+ const unsigned long *src_pfns,
+ const unsigned long *dst_pfns,
+ unsigned long start,
+ unsigned long end,
+ void *private)
+{
+ struct nouveau_dmem_fault *fault = private;
+ struct nouveau_drm *drm = fault->drm;
+
+ if (fault->fence) {
+ nouveau_fence_wait(fault->fence, true, false);
+ nouveau_fence_unref(&fault->fence);
+ } else {
+ /*
+ * FIXME wait for channel to be IDLE before calling finalizing
+ * the hmem object below (nouveau_migrate_hmem_fini()).
+ */
+ }
+
+ while (fault->npages--) {
+ dma_unmap_page(drm->dev->dev, fault->dma[fault->npages],
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ }
+ kfree(fault->dma);
+}
+
+static const struct migrate_vma_ops nouveau_dmem_fault_migrate_ops = {
+ .alloc_and_copy = nouveau_dmem_fault_alloc_and_copy,
+ .finalize_and_map = nouveau_dmem_fault_finalize_and_map,
+};
+
+static int
+nouveau_dmem_fault(struct hmm_devmem *devmem,
+ struct vm_area_struct *vma,
+ unsigned long addr,
+ const struct page *page,
+ unsigned int flags,
+ pmd_t *pmdp)
+{
+ struct drm_device *drm_dev = dev_get_drvdata(devmem->device);
+ unsigned long src[1] = {0}, dst[1] = {0};
+ struct nouveau_dmem_fault fault = {0};
+ int ret;
+
+
+
+ /*
+ * FIXME what we really want is to find some heuristic to migrate more
+ * than just one page on CPU fault. When such fault happens it is very
+ * likely that more surrounding page will CPU fault too.
+ */
+ fault.drm = nouveau_drm(drm_dev);
+ ret = migrate_vma(&nouveau_dmem_fault_migrate_ops, vma, addr,
+ addr + PAGE_SIZE, src, dst, &fault);
+ if (ret)
+ return VM_FAULT_SIGBUS;
+
+ if (dst[0] == MIGRATE_PFN_ERROR)
+ return VM_FAULT_SIGBUS;
+
+ return 0;
+}
+
+static const struct hmm_devmem_ops
+nouveau_dmem_devmem_ops = {
+ .free = nouveau_dmem_free,
+ .fault = nouveau_dmem_fault,
+};
+
+static int
+nouveau_dmem_chunk_alloc(struct nouveau_drm *drm)
+{
+ struct nouveau_dmem_chunk *chunk;
+ int ret;
+
+ if (drm->dmem == NULL)
+ return -EINVAL;
+
+ mutex_lock(&drm->dmem->mutex);
+ chunk = list_first_entry_or_null(&drm->dmem->chunk_empty,
+ struct nouveau_dmem_chunk,
+ list);
+ if (chunk == NULL) {
+ mutex_unlock(&drm->dmem->mutex);
+ return -ENOMEM;
+ }
+
+ list_del(&chunk->list);
+ mutex_unlock(&drm->dmem->mutex);
+
+ ret = nouveau_bo_new(&drm->client, DMEM_CHUNK_SIZE, 0,
+ TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL,
+ &chunk->bo);
+ if (ret)
+ goto out;
+
+ ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+ if (ret) {
+ nouveau_bo_ref(NULL, &chunk->bo);
+ goto out;
+ }
+
+ bitmap_zero(chunk->bitmap, DMEM_CHUNK_NPAGES);
+ spin_lock_init(&chunk->lock);
+
+out:
+ mutex_lock(&drm->dmem->mutex);
+ if (chunk->bo)
+ list_add(&chunk->list, &drm->dmem->chunk_empty);
+ else
+ list_add_tail(&chunk->list, &drm->dmem->chunk_empty);
+ mutex_unlock(&drm->dmem->mutex);
+
+ return ret;
+}
+
+static struct nouveau_dmem_chunk *
+nouveau_dmem_chunk_first_free_locked(struct nouveau_drm *drm)
+{
+ struct nouveau_dmem_chunk *chunk;
+
+ chunk = list_first_entry_or_null(&drm->dmem->chunk_free,
+ struct nouveau_dmem_chunk,
+ list);
+ if (chunk)
+ return chunk;
+
+ chunk = list_first_entry_or_null(&drm->dmem->chunk_empty,
+ struct nouveau_dmem_chunk,
+ list);
+ if (chunk->bo)
+ return chunk;
+
+ return NULL;
+}
+
+static int
+nouveau_dmem_pages_alloc(struct nouveau_drm *drm,
+ unsigned long npages,
+ unsigned long *pages)
+{
+ struct nouveau_dmem_chunk *chunk;
+ unsigned long c;
+ int ret;
+
+ memset(pages, 0xff, npages * sizeof(*pages));
+
+ mutex_lock(&drm->dmem->mutex);
+ for (c = 0; c < npages;) {
+ unsigned long i;
+
+ chunk = nouveau_dmem_chunk_first_free_locked(drm);
+ if (chunk == NULL) {
+ mutex_unlock(&drm->dmem->mutex);
+ ret = nouveau_dmem_chunk_alloc(drm);
+ if (ret) {
+ if (c)
+ break;
+ return ret;
+ }
+ continue;
+ }
+
+ spin_lock(&chunk->lock);
+ i = find_first_zero_bit(chunk->bitmap, DMEM_CHUNK_NPAGES);
+ while (i < DMEM_CHUNK_NPAGES && c < npages) {
+ pages[c] = chunk->pfn_first + i;
+ set_bit(i, chunk->bitmap);
+ chunk->callocated++;
+ c++;
+
+ i = find_next_zero_bit(chunk->bitmap,
+ DMEM_CHUNK_NPAGES, i);
+ }
+ spin_unlock(&chunk->lock);
+ }
+ mutex_unlock(&drm->dmem->mutex);
+
+ return 0;
+}
+
+static struct page *
+nouveau_dmem_page_alloc_locked(struct nouveau_drm *drm)
+{
+ unsigned long pfns[1];
+ struct page *page;
+ int ret;
+
+ /* FIXME stop all the miss-match API ... */
+ ret = nouveau_dmem_pages_alloc(drm, 1, pfns);
+ if (ret)
+ return NULL;
+
+ page = pfn_to_page(pfns[0]);
+ get_page(page);
+ lock_page(page);
+ return page;
+}
+
+static void
+nouveau_dmem_page_free_locked(struct nouveau_drm *drm, struct page *page)
+{
+ unlock_page(page);
+ put_page(page);
+}
+
+void
+nouveau_dmem_resume(struct nouveau_drm *drm)
+{
+ struct nouveau_dmem_chunk *chunk;
+ int ret;
+
+ if (drm->dmem == NULL)
+ return;
+
+ mutex_lock(&drm->dmem->mutex);
+ list_for_each_entry (chunk, &drm->dmem->chunk_free, list) {
+ ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+ /* FIXME handle pin failure */
+ WARN_ON(ret);
+ }
+ list_for_each_entry (chunk, &drm->dmem->chunk_full, list) {
+ ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+ /* FIXME handle pin failure */
+ WARN_ON(ret);
+ }
+ list_for_each_entry (chunk, &drm->dmem->chunk_empty, list) {
+ ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+ /* FIXME handle pin failure */
+ WARN_ON(ret);
+ }
+ mutex_unlock(&drm->dmem->mutex);
+}
+
+void
+nouveau_dmem_suspend(struct nouveau_drm *drm)
+{
+ struct nouveau_dmem_chunk *chunk;
+
+ if (drm->dmem == NULL)
+ return;
+
+ mutex_lock(&drm->dmem->mutex);
+ list_for_each_entry (chunk, &drm->dmem->chunk_free, list) {
+ nouveau_bo_unpin(chunk->bo);
+ }
+ list_for_each_entry (chunk, &drm->dmem->chunk_full, list) {
+ nouveau_bo_unpin(chunk->bo);
+ }
+ list_for_each_entry (chunk, &drm->dmem->chunk_empty, list) {
+ nouveau_bo_unpin(chunk->bo);
+ }
+ mutex_unlock(&drm->dmem->mutex);
+}
+
+void
+nouveau_dmem_fini(struct nouveau_drm *drm)
+{
+ struct nouveau_dmem_chunk *chunk, *tmp;
+
+ if (drm->dmem == NULL)
+ return;
+
+ mutex_lock(&drm->dmem->mutex);
+
+ WARN_ON(!list_empty(&drm->dmem->chunk_free));
+ WARN_ON(!list_empty(&drm->dmem->chunk_full));
+
+ list_for_each_entry_safe (chunk, tmp, &drm->dmem->chunk_empty, list) {
+ if (chunk->bo) {
+ nouveau_bo_unpin(chunk->bo);
+ nouveau_bo_ref(NULL, &chunk->bo);
+ }
+ list_del(&chunk->list);
+ kfree(chunk);
+ }
+
+ mutex_unlock(&drm->dmem->mutex);
+}
+
+static int
+nvc0b5_migrate_copy(struct nouveau_drm *drm, u64 npages,
+ enum nouveau_aper dst_aper, u64 dst_addr,
+ enum nouveau_aper src_aper, u64 src_addr)
+{
+ struct nouveau_channel *chan = drm->dmem->migrate.chan;
+ u32 launch_dma = (1 << 9) /* MULTI_LINE_ENABLE. */ |
+ (1 << 8) /* DST_MEMORY_LAYOUT_PITCH. */ |
+ (1 << 7) /* SRC_MEMORY_LAYOUT_PITCH. */ |
+ (1 << 2) /* FLUSH_ENABLE_TRUE. */ |
+ (2 << 0) /* DATA_TRANSFER_TYPE_NON_PIPELINED. */;
+ int ret;
+
+ ret = RING_SPACE(chan, 13);
+ if (ret)
+ return ret;
+
+ if (src_aper != NOUVEAU_APER_VIRT) {
+ switch (src_aper) {
+ case NOUVEAU_APER_VRAM:
+ BEGIN_IMC0(chan, NvSubCopy, 0x0260, 0);
+ break;
+ case NOUVEAU_APER_HOST:
+ BEGIN_IMC0(chan, NvSubCopy, 0x0260, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ launch_dma |= 0x00001000; /* SRC_TYPE_PHYSICAL. */
+ }
+
+ if (dst_aper != NOUVEAU_APER_VIRT) {
+ switch (dst_aper) {
+ case NOUVEAU_APER_VRAM:
+ BEGIN_IMC0(chan, NvSubCopy, 0x0264, 0);
+ break;
+ case NOUVEAU_APER_HOST:
+ BEGIN_IMC0(chan, NvSubCopy, 0x0264, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ launch_dma |= 0x00002000; /* DST_TYPE_PHYSICAL. */
+ }
+
+ BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8);
+ OUT_RING (chan, upper_32_bits(src_addr));
+ OUT_RING (chan, lower_32_bits(src_addr));
+ OUT_RING (chan, upper_32_bits(dst_addr));
+ OUT_RING (chan, lower_32_bits(dst_addr));
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, npages);
+ BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
+ OUT_RING (chan, launch_dma);
+ return 0;
+}
+
+static int
+nouveau_dmem_migrate_init(struct nouveau_drm *drm)
+{
+ switch (drm->ttm.copy.oclass) {
+ case PASCAL_DMA_COPY_A:
+ case PASCAL_DMA_COPY_B:
+ case VOLTA_DMA_COPY_A:
+ case TURING_DMA_COPY_A:
+ drm->dmem->migrate.copy_func = nvc0b5_migrate_copy;
+ drm->dmem->migrate.chan = drm->ttm.chan;
+ return 0;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
+
+void
+nouveau_dmem_init(struct nouveau_drm *drm)
+{
+ struct device *device = drm->dev->dev;
+ unsigned long i, size;
+ int ret;
+
+ /* This only make sense on PASCAL or newer */
+ if (drm->client.device.info.family < NV_DEVICE_INFO_V0_PASCAL)
+ return;
+
+ if (!(drm->dmem = kzalloc(sizeof(*drm->dmem), GFP_KERNEL)))
+ return;
+
+ mutex_init(&drm->dmem->mutex);
+ INIT_LIST_HEAD(&drm->dmem->chunk_free);
+ INIT_LIST_HEAD(&drm->dmem->chunk_full);
+ INIT_LIST_HEAD(&drm->dmem->chunk_empty);
+
+ size = ALIGN(drm->client.device.info.ram_user, DMEM_CHUNK_SIZE);
+
+ /* Initialize migration dma helpers before registering memory */
+ ret = nouveau_dmem_migrate_init(drm);
+ if (ret) {
+ kfree(drm->dmem);
+ drm->dmem = NULL;
+ return;
+ }
+
+ /*
+ * FIXME we need some kind of policy to decide how much VRAM we
+ * want to register with HMM. For now just register everything
+ * and latter if we want to do thing like over commit then we
+ * could revisit this.
+ */
+ drm->dmem->devmem = hmm_devmem_add(&nouveau_dmem_devmem_ops,
+ device, size);
+ if (drm->dmem->devmem == NULL) {
+ kfree(drm->dmem);
+ drm->dmem = NULL;
+ return;
+ }
+
+ for (i = 0; i < (size / DMEM_CHUNK_SIZE); ++i) {
+ struct nouveau_dmem_chunk *chunk;
+ struct page *page;
+ unsigned long j;
+
+ chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
+ if (chunk == NULL) {
+ nouveau_dmem_fini(drm);
+ return;
+ }
+
+ chunk->drm = drm;
+ chunk->pfn_first = drm->dmem->devmem->pfn_first;
+ chunk->pfn_first += (i * DMEM_CHUNK_NPAGES);
+ list_add_tail(&chunk->list, &drm->dmem->chunk_empty);
+
+ page = pfn_to_page(chunk->pfn_first);
+ for (j = 0; j < DMEM_CHUNK_NPAGES; ++j, ++page) {
+ hmm_devmem_page_set_drvdata(page, (long)chunk);
+ }
+ }
+
+ NV_INFO(drm, "DMEM: registered %ldMB of device memory\n", size >> 20);
+}
+
+static void
+nouveau_dmem_migrate_alloc_and_copy(struct vm_area_struct *vma,
+ const unsigned long *src_pfns,
+ unsigned long *dst_pfns,
+ unsigned long start,
+ unsigned long end,
+ void *private)
+{
+ struct nouveau_migrate *migrate = private;
+ struct nouveau_drm *drm = migrate->drm;
+ struct device *dev = drm->dev->dev;
+ unsigned long addr, i, npages = 0;
+ nouveau_migrate_copy_t copy;
+ int ret;
+
+ /* First allocate new memory */
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, i++) {
+ struct page *dpage, *spage;
+
+ dst_pfns[i] = 0;
+ spage = migrate_pfn_to_page(src_pfns[i]);
+ if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE))
+ continue;
+
+ dpage = nouveau_dmem_page_alloc_locked(drm);
+ if (!dpage)
+ continue;
+
+ dst_pfns[i] = migrate_pfn(page_to_pfn(dpage)) |
+ MIGRATE_PFN_LOCKED |
+ MIGRATE_PFN_DEVICE;
+ npages++;
+ }
+
+ if (!npages)
+ return;
+
+ /* Allocate storage for DMA addresses, so we can unmap later. */
+ migrate->dma = kmalloc(sizeof(*migrate->dma) * npages, GFP_KERNEL);
+ if (!migrate->dma)
+ goto error;
+
+ /* Copy things over */
+ copy = drm->dmem->migrate.copy_func;
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, i++) {
+ struct nouveau_dmem_chunk *chunk;
+ struct page *spage, *dpage;
+ u64 src_addr, dst_addr;
+
+ dpage = migrate_pfn_to_page(dst_pfns[i]);
+ if (!dpage || dst_pfns[i] == MIGRATE_PFN_ERROR)
+ continue;
+
+ chunk = (void *)hmm_devmem_page_get_drvdata(dpage);
+ dst_addr = page_to_pfn(dpage) - chunk->pfn_first;
+ dst_addr = (dst_addr << PAGE_SHIFT) + chunk->bo->bo.offset;
+
+ spage = migrate_pfn_to_page(src_pfns[i]);
+ if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE)) {
+ nouveau_dmem_page_free_locked(drm, dpage);
+ dst_pfns[i] = 0;
+ continue;
+ }
+
+ migrate->dma[migrate->dma_nr] =
+ dma_map_page_attrs(dev, spage, 0, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(dev, migrate->dma[migrate->dma_nr])) {
+ nouveau_dmem_page_free_locked(drm, dpage);
+ dst_pfns[i] = 0;
+ continue;
+ }
+
+ src_addr = migrate->dma[migrate->dma_nr++];
+
+ ret = copy(drm, 1, NOUVEAU_APER_VRAM, dst_addr,
+ NOUVEAU_APER_HOST, src_addr);
+ if (ret) {
+ nouveau_dmem_page_free_locked(drm, dpage);
+ dst_pfns[i] = 0;
+ continue;
+ }
+ }
+
+ nouveau_fence_new(drm->dmem->migrate.chan, false, &migrate->fence);
+
+ return;
+
+error:
+ for (addr = start, i = 0; addr < end; addr += PAGE_SIZE, ++i) {
+ struct page *page;
+
+ if (!dst_pfns[i] || dst_pfns[i] == MIGRATE_PFN_ERROR)
+ continue;
+
+ page = migrate_pfn_to_page(dst_pfns[i]);
+ dst_pfns[i] = MIGRATE_PFN_ERROR;
+ if (page == NULL)
+ continue;
+
+ __free_page(page);
+ }
+}
+
+void nouveau_dmem_migrate_finalize_and_map(struct vm_area_struct *vma,
+ const unsigned long *src_pfns,
+ const unsigned long *dst_pfns,
+ unsigned long start,
+ unsigned long end,
+ void *private)
+{
+ struct nouveau_migrate *migrate = private;
+ struct nouveau_drm *drm = migrate->drm;
+
+ if (migrate->fence) {
+ nouveau_fence_wait(migrate->fence, true, false);
+ nouveau_fence_unref(&migrate->fence);
+ } else {
+ /*
+ * FIXME wait for channel to be IDLE before finalizing
+ * the hmem object below (nouveau_migrate_hmem_fini()) ?
+ */
+ }
+
+ while (migrate->dma_nr--) {
+ dma_unmap_page(drm->dev->dev, migrate->dma[migrate->dma_nr],
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ }
+ kfree(migrate->dma);
+
+ /*
+ * FIXME optimization: update GPU page table to point to newly
+ * migrated memory.
+ */
+}
+
+static const struct migrate_vma_ops nouveau_dmem_migrate_ops = {
+ .alloc_and_copy = nouveau_dmem_migrate_alloc_and_copy,
+ .finalize_and_map = nouveau_dmem_migrate_finalize_and_map,
+};
+
+int
+nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
+ struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+ unsigned long *src_pfns, *dst_pfns, npages;
+ struct nouveau_migrate migrate = {0};
+ unsigned long i, c, max;
+ int ret = 0;
+
+ npages = (end - start) >> PAGE_SHIFT;
+ max = min(SG_MAX_SINGLE_ALLOC, npages);
+ src_pfns = kzalloc(sizeof(long) * max, GFP_KERNEL);
+ if (src_pfns == NULL)
+ return -ENOMEM;
+ dst_pfns = kzalloc(sizeof(long) * max, GFP_KERNEL);
+ if (dst_pfns == NULL) {
+ kfree(src_pfns);
+ return -ENOMEM;
+ }
+
+ migrate.drm = drm;
+ migrate.vma = vma;
+ migrate.npages = npages;
+ for (i = 0; i < npages; i += c) {
+ unsigned long next;
+
+ c = min(SG_MAX_SINGLE_ALLOC, npages);
+ next = start + (c << PAGE_SHIFT);
+ ret = migrate_vma(&nouveau_dmem_migrate_ops, vma, start,
+ next, src_pfns, dst_pfns, &migrate);
+ if (ret)
+ goto out;
+ start = next;
+ }
+
+out:
+ kfree(dst_pfns);
+ kfree(src_pfns);
+ return ret;
+}
+
+static inline bool
+nouveau_dmem_page(struct nouveau_drm *drm, struct page *page)
+{
+ if (!is_device_private_page(page))
+ return false;
+
+ if (drm->dmem->devmem != page->pgmap->data)
+ return false;
+
+ return true;
+}
+
+void
+nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
+ struct hmm_range *range)
+{
+ unsigned long i, npages;
+
+ npages = (range->end - range->start) >> PAGE_SHIFT;
+ for (i = 0; i < npages; ++i) {
+ struct nouveau_dmem_chunk *chunk;
+ struct page *page;
+ uint64_t addr;
+
+ page = hmm_pfn_to_page(range, range->pfns[i]);
+ if (page == NULL)
+ continue;
+
+ if (!(range->pfns[i] & range->flags[HMM_PFN_DEVICE_PRIVATE])) {
+ continue;
+ }
+
+ if (!nouveau_dmem_page(drm, page)) {
+ WARN(1, "Some unknown device memory !\n");
+ range->pfns[i] = 0;
+ continue;
+ }
+
+ chunk = (void *)hmm_devmem_page_get_drvdata(page);
+ addr = page_to_pfn(page) - chunk->pfn_first;
+ addr = (addr + chunk->bo->bo.mem.start) << PAGE_SHIFT;
+
+ range->pfns[i] &= ((1UL << range->pfn_shift) - 1);
+ range->pfns[i] |= (addr >> PAGE_SHIFT) << range->pfn_shift;
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.h b/drivers/gpu/drm/nouveau/nouveau_dmem.h
new file mode 100644
index 000000000000..9d97d756fb7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __NOUVEAU_DMEM_H__
+#define __NOUVEAU_DMEM_H__
+#include <nvif/os.h>
+struct drm_device;
+struct drm_file;
+struct nouveau_drm;
+struct hmm_range;
+
+#if IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)
+void nouveau_dmem_init(struct nouveau_drm *);
+void nouveau_dmem_fini(struct nouveau_drm *);
+void nouveau_dmem_suspend(struct nouveau_drm *);
+void nouveau_dmem_resume(struct nouveau_drm *);
+
+int nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
+ struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end);
+
+void nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
+ struct hmm_range *range);
+#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
+static inline void nouveau_dmem_init(struct nouveau_drm *drm) {}
+static inline void nouveau_dmem_fini(struct nouveau_drm *drm) {}
+static inline void nouveau_dmem_suspend(struct nouveau_drm *drm) {}
+static inline void nouveau_dmem_resume(struct nouveau_drm *drm) {}
+
+static inline int nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
+ struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+ return 0;
+}
+
+static inline void nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
+ struct hmm_range *range) {}
+#endif /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index f900e94592f8..5020265bfbd9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -44,7 +44,6 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cla06f.h>
-#include <nvif/if0004.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@@ -63,6 +62,8 @@
#include "nouveau_usif.h"
#include "nouveau_connector.h"
#include "nouveau_platform.h"
+#include "nouveau_svm.h"
+#include "nouveau_dmem.h"
MODULE_PARM_DESC(config, "option string to pass to driver core");
static char *nouveau_config;
@@ -173,6 +174,7 @@ nouveau_cli_fini(struct nouveau_cli *cli)
WARN_ON(!list_empty(&cli->worker));
usif_client_fini(cli);
+ nouveau_vmm_fini(&cli->svm);
nouveau_vmm_fini(&cli->vmm);
nvif_mmu_fini(&cli->mmu);
nvif_device_fini(&cli->device);
@@ -283,19 +285,134 @@ done:
}
static void
-nouveau_accel_fini(struct nouveau_drm *drm)
+nouveau_accel_ce_fini(struct nouveau_drm *drm)
+{
+ nouveau_channel_idle(drm->cechan);
+ nvif_object_fini(&drm->ttm.copy);
+ nouveau_channel_del(&drm->cechan);
+}
+
+static void
+nouveau_accel_ce_init(struct nouveau_drm *drm)
+{
+ struct nvif_device *device = &drm->client.device;
+ int ret = 0;
+
+ /* Allocate channel that has access to a (preferably async) copy
+ * engine, to use for TTM buffer moves.
+ */
+ if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
+ ret = nouveau_channel_new(drm, device,
+ nvif_fifo_runlist_ce(device), 0,
+ true, &drm->cechan);
+ } else
+ if (device->info.chipset >= 0xa3 &&
+ device->info.chipset != 0xaa &&
+ device->info.chipset != 0xac) {
+ /* Prior to Kepler, there's only a single runlist, so all
+ * engines can be accessed from any channel.
+ *
+ * We still want to use a separate channel though.
+ */
+ ret = nouveau_channel_new(drm, device, NvDmaFB, NvDmaTT, false,
+ &drm->cechan);
+ }
+
+ if (ret)
+ NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
+}
+
+static void
+nouveau_accel_gr_fini(struct nouveau_drm *drm)
{
nouveau_channel_idle(drm->channel);
nvif_object_fini(&drm->ntfy);
nvkm_gpuobj_del(&drm->notify);
- nvif_notify_fini(&drm->flip);
nvif_object_fini(&drm->nvsw);
nouveau_channel_del(&drm->channel);
+}
- nouveau_channel_idle(drm->cechan);
- nvif_object_fini(&drm->ttm.copy);
- nouveau_channel_del(&drm->cechan);
+static void
+nouveau_accel_gr_init(struct nouveau_drm *drm)
+{
+ struct nvif_device *device = &drm->client.device;
+ u32 arg0, arg1;
+ int ret;
+
+ /* Allocate channel that has access to the graphics engine. */
+ if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
+ arg0 = nvif_fifo_runlist(device, NV_DEVICE_INFO_ENGINE_GR);
+ arg1 = 1;
+ } else {
+ arg0 = NvDmaFB;
+ arg1 = NvDmaTT;
+ }
+ ret = nouveau_channel_new(drm, device, arg0, arg1, false,
+ &drm->channel);
+ if (ret) {
+ NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
+ nouveau_accel_gr_fini(drm);
+ return;
+ }
+
+ /* A SW class is used on pre-NV50 HW to assist with handling the
+ * synchronisation of page flips, as well as to implement fences
+ * on TNT/TNT2 HW that lacks any kind of support in host.
+ */
+ if (device->info.family < NV_DEVICE_INFO_V0_TESLA) {
+ ret = nvif_object_init(&drm->channel->user, NVDRM_NVSW,
+ nouveau_abi16_swclass(drm), NULL, 0,
+ &drm->nvsw);
+ if (ret == 0) {
+ ret = RING_SPACE(drm->channel, 2);
+ if (ret == 0) {
+ BEGIN_NV04(drm->channel, NvSubSw, 0, 1);
+ OUT_RING (drm->channel, drm->nvsw.handle);
+ }
+ }
+
+ if (ret) {
+ NV_ERROR(drm, "failed to allocate sw class, %d\n", ret);
+ nouveau_accel_gr_fini(drm);
+ return;
+ }
+ }
+
+ /* NvMemoryToMemoryFormat requires a notifier ctxdma for some reason,
+ * even if notification is never requested, so, allocate a ctxdma on
+ * any GPU where it's possible we'll end up using M2MF for BO moves.
+ */
+ if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
+ ret = nvkm_gpuobj_new(nvxx_device(device), 32, 0, false, NULL,
+ &drm->notify);
+ if (ret) {
+ NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
+ nouveau_accel_gr_fini(drm);
+ return;
+ }
+
+ ret = nvif_object_init(&drm->channel->user, NvNotify0,
+ NV_DMA_IN_MEMORY,
+ &(struct nv_dma_v0) {
+ .target = NV_DMA_V0_TARGET_VRAM,
+ .access = NV_DMA_V0_ACCESS_RDWR,
+ .start = drm->notify->addr,
+ .limit = drm->notify->addr + 31
+ }, sizeof(struct nv_dma_v0),
+ &drm->ntfy);
+ if (ret) {
+ nouveau_accel_gr_fini(drm);
+ return;
+ }
+ }
+}
+
+static void
+nouveau_accel_fini(struct nouveau_drm *drm)
+{
+ nouveau_accel_ce_fini(drm);
+ nouveau_accel_gr_fini(drm);
if (drm->fence)
nouveau_fence(drm)->dtor(drm);
}
@@ -305,23 +422,16 @@ nouveau_accel_init(struct nouveau_drm *drm)
{
struct nvif_device *device = &drm->client.device;
struct nvif_sclass *sclass;
- u32 arg0, arg1;
int ret, i, n;
if (nouveau_noaccel)
return;
+ /* Initialise global support for channels, and synchronisation. */
ret = nouveau_channels_init(drm);
if (ret)
return;
- if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_VOLTA) {
- ret = nvif_user_init(device);
- if (ret)
- return;
- }
-
- /* initialise synchronisation routines */
/*XXX: this is crap, but the fence/channel stuff is a little
* backwards in some places. this will be fixed.
*/
@@ -368,95 +478,18 @@ nouveau_accel_init(struct nouveau_drm *drm)
return;
}
- if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
- ret = nouveau_channel_new(drm, &drm->client.device,
- nvif_fifo_runlist_ce(device), 0,
- true, &drm->cechan);
- if (ret)
- NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
-
- arg0 = nvif_fifo_runlist(device, NV_DEVICE_INFO_ENGINE_GR);
- arg1 = 1;
- } else
- if (device->info.chipset >= 0xa3 &&
- device->info.chipset != 0xaa &&
- device->info.chipset != 0xac) {
- ret = nouveau_channel_new(drm, &drm->client.device,
- NvDmaFB, NvDmaTT, false,
- &drm->cechan);
+ /* Volta requires access to a doorbell register for kickoff. */
+ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_VOLTA) {
+ ret = nvif_user_init(device);
if (ret)
- NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
-
- arg0 = NvDmaFB;
- arg1 = NvDmaTT;
- } else {
- arg0 = NvDmaFB;
- arg1 = NvDmaTT;
- }
-
- ret = nouveau_channel_new(drm, &drm->client.device,
- arg0, arg1, false, &drm->channel);
- if (ret) {
- NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
- nouveau_accel_fini(drm);
- return;
- }
-
- if (device->info.family < NV_DEVICE_INFO_V0_TESLA) {
- ret = nvif_object_init(&drm->channel->user, NVDRM_NVSW,
- nouveau_abi16_swclass(drm), NULL, 0,
- &drm->nvsw);
- if (ret == 0) {
- ret = RING_SPACE(drm->channel, 2);
- if (ret == 0) {
- BEGIN_NV04(drm->channel, NvSubSw, 0, 1);
- OUT_RING (drm->channel, drm->nvsw.handle);
- }
-
- ret = nvif_notify_init(&drm->nvsw,
- nouveau_flip_complete,
- false, NV04_NVSW_NTFY_UEVENT,
- NULL, 0, 0, &drm->flip);
- if (ret == 0)
- ret = nvif_notify_get(&drm->flip);
- if (ret) {
- nouveau_accel_fini(drm);
- return;
- }
- }
-
- if (ret) {
- NV_ERROR(drm, "failed to allocate sw class, %d\n", ret);
- nouveau_accel_fini(drm);
- return;
- }
- }
-
- if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
- ret = nvkm_gpuobj_new(nvxx_device(&drm->client.device), 32, 0,
- false, NULL, &drm->notify);
- if (ret) {
- NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
- nouveau_accel_fini(drm);
return;
- }
-
- ret = nvif_object_init(&drm->channel->user, NvNotify0,
- NV_DMA_IN_MEMORY,
- &(struct nv_dma_v0) {
- .target = NV_DMA_V0_TARGET_VRAM,
- .access = NV_DMA_V0_ACCESS_RDWR,
- .start = drm->notify->addr,
- .limit = drm->notify->addr + 31
- }, sizeof(struct nv_dma_v0),
- &drm->ntfy);
- if (ret) {
- nouveau_accel_fini(drm);
- return;
- }
}
+ /* Allocate channels we need to support various functions. */
+ nouveau_accel_gr_init(drm);
+ nouveau_accel_ce_init(drm);
+ /* Initialise accelerated TTM buffer moves. */
nouveau_bo_move_init(drm);
}
@@ -504,19 +537,22 @@ nouveau_drm_device_init(struct drm_device *dev)
if (ret)
goto fail_bios;
+ nouveau_accel_init(drm);
+
ret = nouveau_display_create(dev);
if (ret)
goto fail_dispctor;
if (dev->mode_config.num_crtc) {
- ret = nouveau_display_init(dev);
+ ret = nouveau_display_init(dev, false, false);
if (ret)
goto fail_dispinit;
}
nouveau_debugfs_init(drm);
nouveau_hwmon_init(dev);
- nouveau_accel_init(drm);
+ nouveau_svm_init(drm);
+ nouveau_dmem_init(drm);
nouveau_fbcon_init(dev);
nouveau_led_init(dev);
@@ -534,6 +570,7 @@ nouveau_drm_device_init(struct drm_device *dev)
fail_dispinit:
nouveau_display_destroy(dev);
fail_dispctor:
+ nouveau_accel_fini(drm);
nouveau_bios_takedown(dev);
fail_bios:
nouveau_ttm_fini(drm);
@@ -559,7 +596,8 @@ nouveau_drm_device_fini(struct drm_device *dev)
nouveau_led_fini(dev);
nouveau_fbcon_fini(dev);
- nouveau_accel_fini(drm);
+ nouveau_dmem_fini(drm);
+ nouveau_svm_fini(drm);
nouveau_hwmon_fini(dev);
nouveau_debugfs_fini(drm);
@@ -567,6 +605,7 @@ nouveau_drm_device_fini(struct drm_device *dev)
nouveau_display_fini(dev, false, false);
nouveau_display_destroy(dev);
+ nouveau_accel_fini(drm);
nouveau_bios_takedown(dev);
nouveau_ttm_fini(drm);
@@ -704,6 +743,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_drm *drm = nouveau_drm(dev);
int ret;
+ nouveau_svm_suspend(drm);
+ nouveau_dmem_suspend(drm);
nouveau_led_suspend(dev);
if (dev->mode_config.num_crtc) {
@@ -780,7 +821,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
}
nouveau_led_resume(dev);
-
+ nouveau_dmem_resume(drm);
+ nouveau_svm_resume(drm);
return 0;
}
@@ -1000,6 +1042,8 @@ nouveau_ioctls[] = {
DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_INIT, nouveau_svmm_init, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_BIND, nouveau_svmm_bind, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index d20b9ba4b1c1..da847244479d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -96,6 +96,7 @@ struct nouveau_cli {
struct nvif_device device;
struct nvif_mmu mmu;
struct nouveau_vmm vmm;
+ struct nouveau_vmm svm;
const struct nvif_mclass *mem;
struct list_head head;
@@ -181,7 +182,6 @@ struct nouveau_drm {
struct nouveau_fbdev *fbcon;
struct nvif_object nvsw;
struct nvif_object ntfy;
- struct nvif_notify flip;
/* nv10-nv40 tiling regions */
struct {
@@ -210,6 +210,10 @@ struct nouveau_drm {
bool have_disp_power_ref;
struct dev_pm_domain vga_pm_domain;
+
+ struct nouveau_svm *svm;
+
+ struct nouveau_dmem *dmem;
};
static inline struct nouveau_drm *
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 032317c81bf0..0d3cd4e05728 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -353,7 +353,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
chan = nouveau_nofbaccel ? NULL : drm->channel;
if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
- ret = nouveau_vma_new(nvbo, &drm->client.vmm, &fb->vma);
+ ret = nouveau_vma_new(nvbo, chan->vmm, &fb->vma);
if (ret) {
NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
chan = NULL;
@@ -374,9 +374,9 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
strcpy(info->fix.id, "nouveaufb");
if (!chan)
- info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED;
+ info->flags = FBINFO_HWACCEL_DISABLED;
else
- info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+ info->flags = FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
info->fbops = &nouveau_fbcon_sw_ops;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index b999e6058046..ad27caeca0fd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -82,8 +82,6 @@ int nv50_fence_create(struct nouveau_drm *);
int nv84_fence_create(struct nouveau_drm *);
int nvc0_fence_create(struct nouveau_drm *);
-int nouveau_flip_complete(struct nvif_notify *);
-
struct nv84_fence_chan {
struct nouveau_fence_chan base;
struct nouveau_vma *vma;
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index b56524d343c3..b4bda716564d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -41,7 +41,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
{
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
- struct ttm_buffer_object *bo = &nvbo->bo;
struct device *dev = drm->dev->dev;
int ret;
@@ -56,7 +55,7 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
/* reset filp so nouveau_bo_del_ttm() can test for it */
gem->filp = NULL;
- ttm_bo_unref(&bo);
+ ttm_bo_put(&nvbo->bo);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -69,10 +68,11 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct device *dev = drm->dev->dev;
+ struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
struct nouveau_vma *vma;
int ret;
- if (cli->vmm.vmm.object.oclass < NVIF_CLASS_VMM_NV50)
+ if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
return 0;
ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
@@ -83,7 +83,7 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
if (ret < 0 && ret != -EACCES)
goto out;
- ret = nouveau_vma_new(nvbo, &cli->vmm, &vma);
+ ret = nouveau_vma_new(nvbo, vmm, &vma);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
out:
@@ -143,17 +143,18 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct device *dev = drm->dev->dev;
+ struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : & cli->vmm;
struct nouveau_vma *vma;
int ret;
- if (cli->vmm.vmm.object.oclass < NVIF_CLASS_VMM_NV50)
+ if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
return;
ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
if (ret)
return;
- vma = nouveau_vma_find(nvbo, &cli->vmm);
+ vma = nouveau_vma_find(nvbo, vmm);
if (vma) {
if (--vma->refs == 0) {
ret = pm_runtime_get_sync(dev);
@@ -220,6 +221,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
+ struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
struct nouveau_vma *vma;
if (is_power_of_2(nvbo->valid_domains))
@@ -229,8 +231,8 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
else
rep->domain = NOUVEAU_GEM_DOMAIN_VRAM;
rep->offset = nvbo->bo.offset;
- if (cli->vmm.vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
- vma = nouveau_vma_find(nvbo, &cli->vmm);
+ if (vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
+ vma = nouveau_vma_find(nvbo, vmm);
if (!vma)
return -EINVAL;
@@ -322,7 +324,8 @@ struct validate_op {
};
static void
-validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence,
+validate_fini_no_ticket(struct validate_op *op, struct nouveau_channel *chan,
+ struct nouveau_fence *fence,
struct drm_nouveau_gem_pushbuf_bo *pbbo)
{
struct nouveau_bo *nvbo;
@@ -333,13 +336,11 @@ validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence,
b = &pbbo[nvbo->pbbo_index];
if (likely(fence)) {
- struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
- struct nouveau_vma *vma;
-
nouveau_bo_fence(nvbo, fence, !!b->write_domains);
- if (drm->client.vmm.vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
- vma = (void *)(unsigned long)b->user_priv;
+ if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
+ struct nouveau_vma *vma =
+ (void *)(unsigned long)b->user_priv;
nouveau_fence_unref(&vma->fence);
dma_fence_get(&fence->base);
vma->fence = fence;
@@ -359,10 +360,11 @@ validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence,
}
static void
-validate_fini(struct validate_op *op, struct nouveau_fence *fence,
+validate_fini(struct validate_op *op, struct nouveau_channel *chan,
+ struct nouveau_fence *fence,
struct drm_nouveau_gem_pushbuf_bo *pbbo)
{
- validate_fini_no_ticket(op, fence, pbbo);
+ validate_fini_no_ticket(op, chan, fence, pbbo);
ww_acquire_fini(&op->ticket);
}
@@ -417,7 +419,7 @@ retry:
list_splice_tail_init(&vram_list, &op->list);
list_splice_tail_init(&gart_list, &op->list);
list_splice_tail_init(&both_list, &op->list);
- validate_fini_no_ticket(op, NULL, NULL);
+ validate_fini_no_ticket(op, chan, NULL, NULL);
if (unlikely(ret == -EDEADLK)) {
ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
&op->ticket);
@@ -431,8 +433,8 @@ retry:
}
}
- if (cli->vmm.vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
- struct nouveau_vmm *vmm = &cli->vmm;
+ if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
+ struct nouveau_vmm *vmm = chan->vmm;
struct nouveau_vma *vma = nouveau_vma_find(nvbo, vmm);
if (!vma) {
NV_PRINTK(err, cli, "vma not found!\n");
@@ -472,7 +474,7 @@ retry:
list_splice_tail(&gart_list, &op->list);
list_splice_tail(&both_list, &op->list);
if (ret)
- validate_fini(op, NULL, NULL);
+ validate_fini(op, chan, NULL, NULL);
return ret;
}
@@ -564,7 +566,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
if (unlikely(ret < 0)) {
if (ret != -ERESTARTSYS)
NV_PRINTK(err, cli, "validating bo list\n");
- validate_fini(op, NULL, NULL);
+ validate_fini(op, chan, NULL, NULL);
return ret;
}
*apply_relocs = ret;
@@ -843,7 +845,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
}
out:
- validate_fini(&op, fence, bo);
+ validate_fini(&op, chan, fence, bo);
nouveau_fence_unref(&fence);
out_prevalid:
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
new file mode 100644
index 000000000000..93ed43c413f0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nouveau_svm.h"
+#include "nouveau_drv.h"
+#include "nouveau_chan.h"
+#include "nouveau_dmem.h"
+
+#include <nvif/notify.h>
+#include <nvif/object.h>
+#include <nvif/vmm.h>
+
+#include <nvif/class.h>
+#include <nvif/clb069.h>
+#include <nvif/ifc00d.h>
+
+#include <linux/sched/mm.h>
+#include <linux/sort.h>
+#include <linux/hmm.h>
+
+struct nouveau_svm {
+ struct nouveau_drm *drm;
+ struct mutex mutex;
+ struct list_head inst;
+
+ struct nouveau_svm_fault_buffer {
+ int id;
+ struct nvif_object object;
+ u32 entries;
+ u32 getaddr;
+ u32 putaddr;
+ u32 get;
+ u32 put;
+ struct nvif_notify notify;
+
+ struct nouveau_svm_fault {
+ u64 inst;
+ u64 addr;
+ u64 time;
+ u32 engine;
+ u8 gpc;
+ u8 hub;
+ u8 access;
+ u8 client;
+ u8 fault;
+ struct nouveau_svmm *svmm;
+ } **fault;
+ int fault_nr;
+ } buffer[1];
+};
+
+#define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
+#define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
+
+struct nouveau_ivmm {
+ struct nouveau_svmm *svmm;
+ u64 inst;
+ struct list_head head;
+};
+
+static struct nouveau_ivmm *
+nouveau_ivmm_find(struct nouveau_svm *svm, u64 inst)
+{
+ struct nouveau_ivmm *ivmm;
+ list_for_each_entry(ivmm, &svm->inst, head) {
+ if (ivmm->inst == inst)
+ return ivmm;
+ }
+ return NULL;
+}
+
+struct nouveau_svmm {
+ struct nouveau_vmm *vmm;
+ struct {
+ unsigned long start;
+ unsigned long limit;
+ } unmanaged;
+
+ struct mutex mutex;
+
+ struct mm_struct *mm;
+ struct hmm_mirror mirror;
+};
+
+#define SVMM_DBG(s,f,a...) \
+ NV_DEBUG((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
+#define SVMM_ERR(s,f,a...) \
+ NV_WARN((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
+
+int
+nouveau_svmm_bind(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct nouveau_cli *cli = nouveau_cli(file_priv);
+ struct drm_nouveau_svm_bind *args = data;
+ unsigned target, cmd, priority;
+ unsigned long addr, end, size;
+ struct mm_struct *mm;
+
+ args->va_start &= PAGE_MASK;
+ args->va_end &= PAGE_MASK;
+
+ /* Sanity check arguments */
+ if (args->reserved0 || args->reserved1)
+ return -EINVAL;
+ if (args->header & (~NOUVEAU_SVM_BIND_VALID_MASK))
+ return -EINVAL;
+ if (args->va_start >= args->va_end)
+ return -EINVAL;
+ if (!args->npages)
+ return -EINVAL;
+
+ cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT;
+ cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK;
+ switch (cmd) {
+ case NOUVEAU_SVM_BIND_COMMAND__MIGRATE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priority = args->header >> NOUVEAU_SVM_BIND_PRIORITY_SHIFT;
+ priority &= NOUVEAU_SVM_BIND_PRIORITY_MASK;
+
+ /* FIXME support CPU target ie all target value < GPU_VRAM */
+ target = args->header >> NOUVEAU_SVM_BIND_TARGET_SHIFT;
+ target &= NOUVEAU_SVM_BIND_TARGET_MASK;
+ switch (target) {
+ case NOUVEAU_SVM_BIND_TARGET__GPU_VRAM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME: For now refuse non 0 stride, we need to change the migrate
+ * kernel function to handle stride to avoid to create a mess within
+ * each device driver.
+ */
+ if (args->stride)
+ return -EINVAL;
+
+ size = ((unsigned long)args->npages) << PAGE_SHIFT;
+ if ((args->va_start + size) <= args->va_start)
+ return -EINVAL;
+ if ((args->va_start + size) > args->va_end)
+ return -EINVAL;
+
+ /*
+ * Ok we are ask to do something sane, for now we only support migrate
+ * commands but we will add things like memory policy (what to do on
+ * page fault) and maybe some other commands.
+ */
+
+ mm = get_task_mm(current);
+ down_read(&mm->mmap_sem);
+
+ for (addr = args->va_start, end = args->va_start + size; addr < end;) {
+ struct vm_area_struct *vma;
+ unsigned long next;
+
+ vma = find_vma_intersection(mm, addr, end);
+ if (!vma)
+ break;
+
+ next = min(vma->vm_end, end);
+ /* This is a best effort so we ignore errors */
+ nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
+ addr = next;
+ }
+
+ /*
+ * FIXME Return the number of page we have migrated, again we need to
+ * update the migrate API to return that information so that we can
+ * report it to user space.
+ */
+ args->result = 0;
+
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+
+ return 0;
+}
+
+/* Unlink channel instance from SVMM. */
+void
+nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst)
+{
+ struct nouveau_ivmm *ivmm;
+ if (svmm) {
+ mutex_lock(&svmm->vmm->cli->drm->svm->mutex);
+ ivmm = nouveau_ivmm_find(svmm->vmm->cli->drm->svm, inst);
+ if (ivmm) {
+ list_del(&ivmm->head);
+ kfree(ivmm);
+ }
+ mutex_unlock(&svmm->vmm->cli->drm->svm->mutex);
+ }
+}
+
+/* Link channel instance to SVMM. */
+int
+nouveau_svmm_join(struct nouveau_svmm *svmm, u64 inst)
+{
+ struct nouveau_ivmm *ivmm;
+ if (svmm) {
+ if (!(ivmm = kmalloc(sizeof(*ivmm), GFP_KERNEL)))
+ return -ENOMEM;
+ ivmm->svmm = svmm;
+ ivmm->inst = inst;
+
+ mutex_lock(&svmm->vmm->cli->drm->svm->mutex);
+ list_add(&ivmm->head, &svmm->vmm->cli->drm->svm->inst);
+ mutex_unlock(&svmm->vmm->cli->drm->svm->mutex);
+ }
+ return 0;
+}
+
+/* Invalidate SVMM address-range on GPU. */
+static void
+nouveau_svmm_invalidate(struct nouveau_svmm *svmm, u64 start, u64 limit)
+{
+ if (limit > start) {
+ bool super = svmm->vmm->vmm.object.client->super;
+ svmm->vmm->vmm.object.client->super = true;
+ nvif_object_mthd(&svmm->vmm->vmm.object, NVIF_VMM_V0_PFNCLR,
+ &(struct nvif_vmm_pfnclr_v0) {
+ .addr = start,
+ .size = limit - start,
+ }, sizeof(struct nvif_vmm_pfnclr_v0));
+ svmm->vmm->vmm.object.client->super = super;
+ }
+}
+
+static int
+nouveau_svmm_sync_cpu_device_pagetables(struct hmm_mirror *mirror,
+ const struct hmm_update *update)
+{
+ struct nouveau_svmm *svmm = container_of(mirror, typeof(*svmm), mirror);
+ unsigned long start = update->start;
+ unsigned long limit = update->end;
+
+ if (!update->blockable)
+ return -EAGAIN;
+
+ SVMM_DBG(svmm, "invalidate %016lx-%016lx", start, limit);
+
+ mutex_lock(&svmm->mutex);
+ if (limit > svmm->unmanaged.start && start < svmm->unmanaged.limit) {
+ if (start < svmm->unmanaged.start) {
+ nouveau_svmm_invalidate(svmm, start,
+ svmm->unmanaged.limit);
+ }
+ start = svmm->unmanaged.limit;
+ }
+
+ nouveau_svmm_invalidate(svmm, start, limit);
+ mutex_unlock(&svmm->mutex);
+ return 0;
+}
+
+static void
+nouveau_svmm_release(struct hmm_mirror *mirror)
+{
+}
+
+static const struct hmm_mirror_ops
+nouveau_svmm = {
+ .sync_cpu_device_pagetables = nouveau_svmm_sync_cpu_device_pagetables,
+ .release = nouveau_svmm_release,
+};
+
+void
+nouveau_svmm_fini(struct nouveau_svmm **psvmm)
+{
+ struct nouveau_svmm *svmm = *psvmm;
+ if (svmm) {
+ hmm_mirror_unregister(&svmm->mirror);
+ kfree(*psvmm);
+ *psvmm = NULL;
+ }
+}
+
+int
+nouveau_svmm_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct nouveau_cli *cli = nouveau_cli(file_priv);
+ struct nouveau_svmm *svmm;
+ struct drm_nouveau_svm_init *args = data;
+ int ret;
+
+ /* Allocate tracking for SVM-enabled VMM. */
+ if (!(svmm = kzalloc(sizeof(*svmm), GFP_KERNEL)))
+ return -ENOMEM;
+ svmm->vmm = &cli->svm;
+ svmm->unmanaged.start = args->unmanaged_addr;
+ svmm->unmanaged.limit = args->unmanaged_addr + args->unmanaged_size;
+ mutex_init(&svmm->mutex);
+
+ /* Check that SVM isn't already enabled for the client. */
+ mutex_lock(&cli->mutex);
+ if (cli->svm.cli) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ /* Allocate a new GPU VMM that can support SVM (managed by the
+ * client, with replayable faults enabled).
+ *
+ * All future channel/memory allocations will make use of this
+ * VMM instead of the standard one.
+ */
+ ret = nvif_vmm_init(&cli->mmu, cli->vmm.vmm.object.oclass, true,
+ args->unmanaged_addr, args->unmanaged_size,
+ &(struct gp100_vmm_v0) {
+ .fault_replay = true,
+ }, sizeof(struct gp100_vmm_v0), &cli->svm.vmm);
+ if (ret)
+ goto done;
+
+ /* Enable HMM mirroring of CPU address-space to VMM. */
+ svmm->mm = get_task_mm(current);
+ down_write(&svmm->mm->mmap_sem);
+ svmm->mirror.ops = &nouveau_svmm;
+ ret = hmm_mirror_register(&svmm->mirror, svmm->mm);
+ if (ret == 0) {
+ cli->svm.svmm = svmm;
+ cli->svm.cli = cli;
+ }
+ up_write(&svmm->mm->mmap_sem);
+ mmput(svmm->mm);
+
+done:
+ if (ret)
+ nouveau_svmm_fini(&svmm);
+ mutex_unlock(&cli->mutex);
+ return ret;
+}
+
+static const u64
+nouveau_svm_pfn_flags[HMM_PFN_FLAG_MAX] = {
+ [HMM_PFN_VALID ] = NVIF_VMM_PFNMAP_V0_V,
+ [HMM_PFN_WRITE ] = NVIF_VMM_PFNMAP_V0_W,
+ [HMM_PFN_DEVICE_PRIVATE] = NVIF_VMM_PFNMAP_V0_VRAM,
+};
+
+static const u64
+nouveau_svm_pfn_values[HMM_PFN_VALUE_MAX] = {
+ [HMM_PFN_ERROR ] = ~NVIF_VMM_PFNMAP_V0_V,
+ [HMM_PFN_NONE ] = NVIF_VMM_PFNMAP_V0_NONE,
+ [HMM_PFN_SPECIAL] = ~NVIF_VMM_PFNMAP_V0_V,
+};
+
+/* Issue fault replay for GPU to retry accesses that faulted previously. */
+static void
+nouveau_svm_fault_replay(struct nouveau_svm *svm)
+{
+ SVM_DBG(svm, "replay");
+ WARN_ON(nvif_object_mthd(&svm->drm->client.vmm.vmm.object,
+ GP100_VMM_VN_FAULT_REPLAY,
+ &(struct gp100_vmm_fault_replay_vn) {},
+ sizeof(struct gp100_vmm_fault_replay_vn)));
+}
+
+/* Cancel a replayable fault that could not be handled.
+ *
+ * Cancelling the fault will trigger recovery to reset the engine
+ * and kill the offending channel (ie. GPU SIGSEGV).
+ */
+static void
+nouveau_svm_fault_cancel(struct nouveau_svm *svm,
+ u64 inst, u8 hub, u8 gpc, u8 client)
+{
+ SVM_DBG(svm, "cancel %016llx %d %02x %02x", inst, hub, gpc, client);
+ WARN_ON(nvif_object_mthd(&svm->drm->client.vmm.vmm.object,
+ GP100_VMM_VN_FAULT_CANCEL,
+ &(struct gp100_vmm_fault_cancel_v0) {
+ .hub = hub,
+ .gpc = gpc,
+ .client = client,
+ .inst = inst,
+ }, sizeof(struct gp100_vmm_fault_cancel_v0)));
+}
+
+static void
+nouveau_svm_fault_cancel_fault(struct nouveau_svm *svm,
+ struct nouveau_svm_fault *fault)
+{
+ nouveau_svm_fault_cancel(svm, fault->inst,
+ fault->hub,
+ fault->gpc,
+ fault->client);
+}
+
+static int
+nouveau_svm_fault_cmp(const void *a, const void *b)
+{
+ const struct nouveau_svm_fault *fa = *(struct nouveau_svm_fault **)a;
+ const struct nouveau_svm_fault *fb = *(struct nouveau_svm_fault **)b;
+ int ret;
+ if ((ret = (s64)fa->inst - fb->inst))
+ return ret;
+ if ((ret = (s64)fa->addr - fb->addr))
+ return ret;
+ /*XXX: atomic? */
+ return (fa->access == 0 || fa->access == 3) -
+ (fb->access == 0 || fb->access == 3);
+}
+
+static void
+nouveau_svm_fault_cache(struct nouveau_svm *svm,
+ struct nouveau_svm_fault_buffer *buffer, u32 offset)
+{
+ struct nvif_object *memory = &buffer->object;
+ const u32 instlo = nvif_rd32(memory, offset + 0x00);
+ const u32 insthi = nvif_rd32(memory, offset + 0x04);
+ const u32 addrlo = nvif_rd32(memory, offset + 0x08);
+ const u32 addrhi = nvif_rd32(memory, offset + 0x0c);
+ const u32 timelo = nvif_rd32(memory, offset + 0x10);
+ const u32 timehi = nvif_rd32(memory, offset + 0x14);
+ const u32 engine = nvif_rd32(memory, offset + 0x18);
+ const u32 info = nvif_rd32(memory, offset + 0x1c);
+ const u64 inst = (u64)insthi << 32 | instlo;
+ const u8 gpc = (info & 0x1f000000) >> 24;
+ const u8 hub = (info & 0x00100000) >> 20;
+ const u8 client = (info & 0x00007f00) >> 8;
+ struct nouveau_svm_fault *fault;
+
+ //XXX: i think we're supposed to spin waiting */
+ if (WARN_ON(!(info & 0x80000000)))
+ return;
+
+ nvif_mask(memory, offset + 0x1c, 0x80000000, 0x00000000);
+
+ if (!buffer->fault[buffer->fault_nr]) {
+ fault = kmalloc(sizeof(*fault), GFP_KERNEL);
+ if (WARN_ON(!fault)) {
+ nouveau_svm_fault_cancel(svm, inst, hub, gpc, client);
+ return;
+ }
+ buffer->fault[buffer->fault_nr] = fault;
+ }
+
+ fault = buffer->fault[buffer->fault_nr++];
+ fault->inst = inst;
+ fault->addr = (u64)addrhi << 32 | addrlo;
+ fault->time = (u64)timehi << 32 | timelo;
+ fault->engine = engine;
+ fault->gpc = gpc;
+ fault->hub = hub;
+ fault->access = (info & 0x000f0000) >> 16;
+ fault->client = client;
+ fault->fault = (info & 0x0000001f);
+
+ SVM_DBG(svm, "fault %016llx %016llx %02x",
+ fault->inst, fault->addr, fault->access);
+}
+
+static int
+nouveau_svm_fault(struct nvif_notify *notify)
+{
+ struct nouveau_svm_fault_buffer *buffer =
+ container_of(notify, typeof(*buffer), notify);
+ struct nouveau_svm *svm =
+ container_of(buffer, typeof(*svm), buffer[buffer->id]);
+ struct nvif_object *device = &svm->drm->client.device.object;
+ struct nouveau_svmm *svmm;
+ struct {
+ struct {
+ struct nvif_ioctl_v0 i;
+ struct nvif_ioctl_mthd_v0 m;
+ struct nvif_vmm_pfnmap_v0 p;
+ } i;
+ u64 phys[16];
+ } args;
+ struct hmm_range range;
+ struct vm_area_struct *vma;
+ u64 inst, start, limit;
+ int fi, fn, pi, fill;
+ int replay = 0, ret;
+
+ /* Parse available fault buffer entries into a cache, and update
+ * the GET pointer so HW can reuse the entries.
+ */
+ SVM_DBG(svm, "fault handler");
+ if (buffer->get == buffer->put) {
+ buffer->put = nvif_rd32(device, buffer->putaddr);
+ buffer->get = nvif_rd32(device, buffer->getaddr);
+ if (buffer->get == buffer->put)
+ return NVIF_NOTIFY_KEEP;
+ }
+ buffer->fault_nr = 0;
+
+ SVM_DBG(svm, "get %08x put %08x", buffer->get, buffer->put);
+ while (buffer->get != buffer->put) {
+ nouveau_svm_fault_cache(svm, buffer, buffer->get * 0x20);
+ if (++buffer->get == buffer->entries)
+ buffer->get = 0;
+ }
+ nvif_wr32(device, buffer->getaddr, buffer->get);
+ SVM_DBG(svm, "%d fault(s) pending", buffer->fault_nr);
+
+ /* Sort parsed faults by instance pointer to prevent unnecessary
+ * instance to SVMM translations, followed by address and access
+ * type to reduce the amount of work when handling the faults.
+ */
+ sort(buffer->fault, buffer->fault_nr, sizeof(*buffer->fault),
+ nouveau_svm_fault_cmp, NULL);
+
+ /* Lookup SVMM structure for each unique instance pointer. */
+ mutex_lock(&svm->mutex);
+ for (fi = 0, svmm = NULL; fi < buffer->fault_nr; fi++) {
+ if (!svmm || buffer->fault[fi]->inst != inst) {
+ struct nouveau_ivmm *ivmm =
+ nouveau_ivmm_find(svm, buffer->fault[fi]->inst);
+ svmm = ivmm ? ivmm->svmm : NULL;
+ inst = buffer->fault[fi]->inst;
+ SVM_DBG(svm, "inst %016llx -> svm-%p", inst, svmm);
+ }
+ buffer->fault[fi]->svmm = svmm;
+ }
+ mutex_unlock(&svm->mutex);
+
+ /* Process list of faults. */
+ args.i.i.version = 0;
+ args.i.i.type = NVIF_IOCTL_V0_MTHD;
+ args.i.m.version = 0;
+ args.i.m.method = NVIF_VMM_V0_PFNMAP;
+ args.i.p.version = 0;
+
+ for (fi = 0; fn = fi + 1, fi < buffer->fault_nr; fi = fn) {
+ /* Cancel any faults from non-SVM channels. */
+ if (!(svmm = buffer->fault[fi]->svmm)) {
+ nouveau_svm_fault_cancel_fault(svm, buffer->fault[fi]);
+ continue;
+ }
+ SVMM_DBG(svmm, "addr %016llx", buffer->fault[fi]->addr);
+
+ /* We try and group handling of faults within a small
+ * window into a single update.
+ */
+ start = buffer->fault[fi]->addr;
+ limit = start + (ARRAY_SIZE(args.phys) << PAGE_SHIFT);
+ if (start < svmm->unmanaged.limit)
+ limit = min_t(u64, limit, svmm->unmanaged.start);
+ else
+ if (limit > svmm->unmanaged.start)
+ start = max_t(u64, start, svmm->unmanaged.limit);
+ SVMM_DBG(svmm, "wndw %016llx-%016llx", start, limit);
+
+ /* Intersect fault window with the CPU VMA, cancelling
+ * the fault if the address is invalid.
+ */
+ down_read(&svmm->mm->mmap_sem);
+ vma = find_vma_intersection(svmm->mm, start, limit);
+ if (!vma) {
+ SVMM_ERR(svmm, "wndw %016llx-%016llx", start, limit);
+ up_read(&svmm->mm->mmap_sem);
+ nouveau_svm_fault_cancel_fault(svm, buffer->fault[fi]);
+ continue;
+ }
+ start = max_t(u64, start, vma->vm_start);
+ limit = min_t(u64, limit, vma->vm_end);
+ SVMM_DBG(svmm, "wndw %016llx-%016llx", start, limit);
+
+ if (buffer->fault[fi]->addr != start) {
+ SVMM_ERR(svmm, "addr %016llx", buffer->fault[fi]->addr);
+ up_read(&svmm->mm->mmap_sem);
+ nouveau_svm_fault_cancel_fault(svm, buffer->fault[fi]);
+ continue;
+ }
+
+ /* Prepare the GPU-side update of all pages within the
+ * fault window, determining required pages and access
+ * permissions based on pending faults.
+ */
+ args.i.p.page = PAGE_SHIFT;
+ args.i.p.addr = start;
+ for (fn = fi, pi = 0;;) {
+ /* Determine required permissions based on GPU fault
+ * access flags.
+ *XXX: atomic?
+ */
+ if (buffer->fault[fn]->access != 0 /* READ. */ &&
+ buffer->fault[fn]->access != 3 /* PREFETCH. */) {
+ args.phys[pi++] = NVIF_VMM_PFNMAP_V0_V |
+ NVIF_VMM_PFNMAP_V0_W;
+ } else {
+ args.phys[pi++] = NVIF_VMM_PFNMAP_V0_V;
+ }
+ args.i.p.size = pi << PAGE_SHIFT;
+
+ /* It's okay to skip over duplicate addresses from the
+ * same SVMM as faults are ordered by access type such
+ * that only the first one needs to be handled.
+ *
+ * ie. WRITE faults appear first, thus any handling of
+ * pending READ faults will already be satisfied.
+ */
+ while (++fn < buffer->fault_nr &&
+ buffer->fault[fn]->svmm == svmm &&
+ buffer->fault[fn ]->addr ==
+ buffer->fault[fn - 1]->addr);
+
+ /* If the next fault is outside the window, or all GPU
+ * faults have been dealt with, we're done here.
+ */
+ if (fn >= buffer->fault_nr ||
+ buffer->fault[fn]->svmm != svmm ||
+ buffer->fault[fn]->addr >= limit)
+ break;
+
+ /* Fill in the gap between this fault and the next. */
+ fill = (buffer->fault[fn ]->addr -
+ buffer->fault[fn - 1]->addr) >> PAGE_SHIFT;
+ while (--fill)
+ args.phys[pi++] = NVIF_VMM_PFNMAP_V0_NONE;
+ }
+
+ SVMM_DBG(svmm, "wndw %016llx-%016llx covering %d fault(s)",
+ args.i.p.addr,
+ args.i.p.addr + args.i.p.size, fn - fi);
+
+ /* Have HMM fault pages within the fault window to the GPU. */
+ range.vma = vma;
+ range.start = args.i.p.addr;
+ range.end = args.i.p.addr + args.i.p.size;
+ range.pfns = args.phys;
+ range.flags = nouveau_svm_pfn_flags;
+ range.values = nouveau_svm_pfn_values;
+ range.pfn_shift = NVIF_VMM_PFNMAP_V0_ADDR_SHIFT;
+again:
+ ret = hmm_vma_fault(&range, true);
+ if (ret == 0) {
+ mutex_lock(&svmm->mutex);
+ if (!hmm_vma_range_done(&range)) {
+ mutex_unlock(&svmm->mutex);
+ goto again;
+ }
+
+ nouveau_dmem_convert_pfn(svm->drm, &range);
+
+ svmm->vmm->vmm.object.client->super = true;
+ ret = nvif_object_ioctl(&svmm->vmm->vmm.object,
+ &args, sizeof(args.i) +
+ pi * sizeof(args.phys[0]),
+ NULL);
+ svmm->vmm->vmm.object.client->super = false;
+ mutex_unlock(&svmm->mutex);
+ }
+ up_read(&svmm->mm->mmap_sem);
+
+ /* Cancel any faults in the window whose pages didn't manage
+ * to keep their valid bit, or stay writeable when required.
+ *
+ * If handling failed completely, cancel all faults.
+ */
+ while (fi < fn) {
+ struct nouveau_svm_fault *fault = buffer->fault[fi++];
+ pi = (fault->addr - range.start) >> PAGE_SHIFT;
+ if (ret ||
+ !(range.pfns[pi] & NVIF_VMM_PFNMAP_V0_V) ||
+ (!(range.pfns[pi] & NVIF_VMM_PFNMAP_V0_W) &&
+ fault->access != 0 && fault->access != 3)) {
+ nouveau_svm_fault_cancel_fault(svm, fault);
+ continue;
+ }
+ replay++;
+ }
+ }
+
+ /* Issue fault replay to the GPU. */
+ if (replay)
+ nouveau_svm_fault_replay(svm);
+ return NVIF_NOTIFY_KEEP;
+}
+
+static void
+nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
+{
+ struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
+ nvif_notify_put(&buffer->notify);
+}
+
+static int
+nouveau_svm_fault_buffer_init(struct nouveau_svm *svm, int id)
+{
+ struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
+ struct nvif_object *device = &svm->drm->client.device.object;
+ buffer->get = nvif_rd32(device, buffer->getaddr);
+ buffer->put = nvif_rd32(device, buffer->putaddr);
+ SVM_DBG(svm, "get %08x put %08x (init)", buffer->get, buffer->put);
+ return nvif_notify_get(&buffer->notify);
+}
+
+static void
+nouveau_svm_fault_buffer_dtor(struct nouveau_svm *svm, int id)
+{
+ struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
+ int i;
+
+ if (buffer->fault) {
+ for (i = 0; buffer->fault[i] && i < buffer->entries; i++)
+ kfree(buffer->fault[i]);
+ kvfree(buffer->fault);
+ }
+
+ nouveau_svm_fault_buffer_fini(svm, id);
+
+ nvif_notify_fini(&buffer->notify);
+ nvif_object_fini(&buffer->object);
+}
+
+static int
+nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)
+{
+ struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
+ struct nouveau_drm *drm = svm->drm;
+ struct nvif_object *device = &drm->client.device.object;
+ struct nvif_clb069_v0 args = {};
+ int ret;
+
+ buffer->id = id;
+
+ ret = nvif_object_init(device, 0, oclass, &args, sizeof(args),
+ &buffer->object);
+ if (ret < 0) {
+ SVM_ERR(svm, "Fault buffer allocation failed: %d", ret);
+ return ret;
+ }
+
+ nvif_object_map(&buffer->object, NULL, 0);
+ buffer->entries = args.entries;
+ buffer->getaddr = args.get;
+ buffer->putaddr = args.put;
+
+ ret = nvif_notify_init(&buffer->object, nouveau_svm_fault, true,
+ NVB069_V0_NTFY_FAULT, NULL, 0, 0,
+ &buffer->notify);
+ if (ret)
+ return ret;
+
+ buffer->fault = kvzalloc(sizeof(*buffer->fault) * buffer->entries, GFP_KERNEL);
+ if (!buffer->fault)
+ return -ENOMEM;
+
+ return nouveau_svm_fault_buffer_init(svm, id);
+}
+
+void
+nouveau_svm_resume(struct nouveau_drm *drm)
+{
+ struct nouveau_svm *svm = drm->svm;
+ if (svm)
+ nouveau_svm_fault_buffer_init(svm, 0);
+}
+
+void
+nouveau_svm_suspend(struct nouveau_drm *drm)
+{
+ struct nouveau_svm *svm = drm->svm;
+ if (svm)
+ nouveau_svm_fault_buffer_fini(svm, 0);
+}
+
+void
+nouveau_svm_fini(struct nouveau_drm *drm)
+{
+ struct nouveau_svm *svm = drm->svm;
+ if (svm) {
+ nouveau_svm_fault_buffer_dtor(svm, 0);
+ kfree(drm->svm);
+ drm->svm = NULL;
+ }
+}
+
+void
+nouveau_svm_init(struct nouveau_drm *drm)
+{
+ static const struct nvif_mclass buffers[] = {
+ { VOLTA_FAULT_BUFFER_A, 0 },
+ { MAXWELL_FAULT_BUFFER_A, 0 },
+ {}
+ };
+ struct nouveau_svm *svm;
+ int ret;
+
+ /* Disable on Volta and newer until channel recovery is fixed,
+ * otherwise clients will have a trivial way to trash the GPU
+ * for everyone.
+ */
+ if (drm->client.device.info.family > NV_DEVICE_INFO_V0_PASCAL)
+ return;
+
+ if (!(drm->svm = svm = kzalloc(sizeof(*drm->svm), GFP_KERNEL)))
+ return;
+
+ drm->svm->drm = drm;
+ mutex_init(&drm->svm->mutex);
+ INIT_LIST_HEAD(&drm->svm->inst);
+
+ ret = nvif_mclass(&drm->client.device.object, buffers);
+ if (ret < 0) {
+ SVM_DBG(svm, "No supported fault buffer class");
+ nouveau_svm_fini(drm);
+ return;
+ }
+
+ ret = nouveau_svm_fault_buffer_ctor(svm, buffers[ret].oclass, 0);
+ if (ret) {
+ nouveau_svm_fini(drm);
+ return;
+ }
+
+ SVM_DBG(svm, "Initialised");
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.h b/drivers/gpu/drm/nouveau/nouveau_svm.h
new file mode 100644
index 000000000000..e839d8189461
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.h
@@ -0,0 +1,48 @@
+#ifndef __NOUVEAU_SVM_H__
+#define __NOUVEAU_SVM_H__
+#include <nvif/os.h>
+struct drm_device;
+struct drm_file;
+struct nouveau_drm;
+
+struct nouveau_svmm;
+
+#if IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)
+void nouveau_svm_init(struct nouveau_drm *);
+void nouveau_svm_fini(struct nouveau_drm *);
+void nouveau_svm_suspend(struct nouveau_drm *);
+void nouveau_svm_resume(struct nouveau_drm *);
+
+int nouveau_svmm_init(struct drm_device *, void *, struct drm_file *);
+void nouveau_svmm_fini(struct nouveau_svmm **);
+int nouveau_svmm_join(struct nouveau_svmm *, u64 inst);
+void nouveau_svmm_part(struct nouveau_svmm *, u64 inst);
+int nouveau_svmm_bind(struct drm_device *, void *, struct drm_file *);
+#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
+static inline void nouveau_svm_init(struct nouveau_drm *drm) {}
+static inline void nouveau_svm_fini(struct nouveau_drm *drm) {}
+static inline void nouveau_svm_suspend(struct nouveau_drm *drm) {}
+static inline void nouveau_svm_resume(struct nouveau_drm *drm) {}
+
+static inline int nouveau_svmm_init(struct drm_device *device, void *p,
+ struct drm_file *file)
+{
+ return -ENOSYS;
+}
+
+static inline void nouveau_svmm_fini(struct nouveau_svmm **svmmp) {}
+
+static inline int nouveau_svmm_join(struct nouveau_svmm *svmm, u64 inst)
+{
+ return 0;
+}
+
+static inline void nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst) {}
+
+static inline int nouveau_svmm_bind(struct drm_device *device, void *p,
+ struct drm_file *file)
+{
+ return -ENOSYS;
+}
+#endif /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.c b/drivers/gpu/drm/nouveau/nouveau_vmm.c
index 2032c3e4f6e5..77061182a1cf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vmm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vmm.c
@@ -22,6 +22,7 @@
#include "nouveau_vmm.h"
#include "nouveau_drv.h"
#include "nouveau_bo.h"
+#include "nouveau_svm.h"
#include "nouveau_mem.h"
void
@@ -119,6 +120,7 @@ done:
void
nouveau_vmm_fini(struct nouveau_vmm *vmm)
{
+ nouveau_svmm_fini(&vmm->svmm);
nvif_vmm_fini(&vmm->vmm);
vmm->cli = NULL;
}
@@ -126,7 +128,7 @@ nouveau_vmm_fini(struct nouveau_vmm *vmm)
int
nouveau_vmm_init(struct nouveau_cli *cli, s32 oclass, struct nouveau_vmm *vmm)
{
- int ret = nvif_vmm_init(&cli->mmu, oclass, PAGE_SIZE, 0, NULL, 0,
+ int ret = nvif_vmm_init(&cli->mmu, oclass, false, PAGE_SIZE, 0, NULL, 0,
&vmm->vmm);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.h b/drivers/gpu/drm/nouveau/nouveau_vmm.h
index ede872f6f668..2b98d975f37e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vmm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_vmm.h
@@ -25,6 +25,7 @@ void nouveau_vma_unmap(struct nouveau_vma *);
struct nouveau_vmm {
struct nouveau_cli *cli;
struct nvif_vmm vmm;
+ struct nouveau_svmm *svmm;
};
int nouveau_vmm_init(struct nouveau_cli *, s32 oclass, struct nouveau_vmm *);
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index e721bb2163a0..f07da00f285f 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -109,7 +109,6 @@ nv84_fence_context_del(struct nouveau_channel *chan)
int
nv84_fence_context_new(struct nouveau_channel *chan)
{
- struct nouveau_cli *cli = (void *)chan->user.client;
struct nv84_fence_priv *priv = chan->drm->fence;
struct nv84_fence_chan *fctx;
int ret;
@@ -127,7 +126,7 @@ nv84_fence_context_new(struct nouveau_channel *chan)
fctx->base.sequence = nv84_fence_read(chan);
mutex_lock(&priv->mutex);
- ret = nouveau_vma_new(priv->bo, &cli->vmm, &fctx->vma);
+ ret = nouveau_vma_new(priv->bo, chan->vmm, &fctx->vma);
mutex_unlock(&priv->mutex);
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c
index ef97dd223a32..61638b3b9d3d 100644
--- a/drivers/gpu/drm/nouveau/nvif/disp.c
+++ b/drivers/gpu/drm/nouveau/nvif/disp.c
@@ -34,7 +34,7 @@ int
nvif_disp_ctor(struct nvif_device *device, s32 oclass, struct nvif_disp *disp)
{
static const struct nvif_mclass disps[] = {
- { TU104_DISP, -1 },
+ { TU102_DISP, -1 },
{ GV100_DISP, -1 },
{ GP102_DISP, -1 },
{ GP100_DISP, -1 },
diff --git a/drivers/gpu/drm/nouveau/nvif/vmm.c b/drivers/gpu/drm/nouveau/nvif/vmm.c
index 6b9c5776547f..11487c00b909 100644
--- a/drivers/gpu/drm/nouveau/nvif/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvif/vmm.c
@@ -112,8 +112,8 @@ nvif_vmm_fini(struct nvif_vmm *vmm)
}
int
-nvif_vmm_init(struct nvif_mmu *mmu, s32 oclass, u64 addr, u64 size,
- void *argv, u32 argc, struct nvif_vmm *vmm)
+nvif_vmm_init(struct nvif_mmu *mmu, s32 oclass, bool managed, u64 addr,
+ u64 size, void *argv, u32 argc, struct nvif_vmm *vmm)
{
struct nvif_vmm_v0 *args;
u32 argn = sizeof(*args) + argc;
@@ -125,6 +125,7 @@ nvif_vmm_init(struct nvif_mmu *mmu, s32 oclass, u64 addr, u64 size,
if (!(args = kmalloc(argn, GFP_KERNEL)))
return -ENOMEM;
args->version = 0;
+ args->managed = managed;
args->addr = addr;
args->size = size;
memcpy(args->data, argv, argc);
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
index c61b467cf45e..245990de1e90 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
@@ -39,6 +39,7 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = {
[NVKM_SUBDEV_FB ] = "fb",
[NVKM_SUBDEV_FUSE ] = "fuse",
[NVKM_SUBDEV_GPIO ] = "gpio",
+ [NVKM_SUBDEV_GSP ] = "gsp",
[NVKM_SUBDEV_I2C ] = "i2c",
[NVKM_SUBDEV_IBUS ] = "priv",
[NVKM_SUBDEV_ICCSENSE] = "iccsense",
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
index 177a23301d6a..9211663239af 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
@@ -6,4 +6,4 @@ nvkm-y += nvkm/engine/ce/gm200.o
nvkm-y += nvkm/engine/ce/gp100.o
nvkm-y += nvkm/engine/ce/gp102.o
nvkm-y += nvkm/engine/ce/gv100.o
-nvkm-y += nvkm/engine/ce/tu104.o
+nvkm-y += nvkm/engine/ce/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c
index 3c25043bbb33..b4308e2d8c75 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu102.c
@@ -24,7 +24,7 @@
#include <nvif/class.h>
static const struct nvkm_engine_func
-tu104_ce = {
+tu102_ce = {
.intr = gp100_ce_intr,
.sclass = {
{ -1, -1, TURING_DMA_COPY_A },
@@ -33,8 +33,8 @@ tu104_ce = {
};
int
-tu104_ce_new(struct nvkm_device *device, int index,
+tu102_ce_new(struct nvkm_device *device, int index,
struct nvkm_engine **pengine)
{
- return nvkm_engine_new_(&tu104_ce, device, index, true, pengine);
+ return nvkm_engine_new_(&tu102_ce, device, index, true, pengine);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index bfbc9341e0c2..7971096b6767 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -1613,7 +1613,7 @@ nvd7_chipset = {
.pci = gf106_pci_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
- .volt = gf100_volt_new,
+ .volt = gf117_volt_new,
.ce[0] = gf100_ce_new,
.disp = gf119_disp_new,
.dma = gf119_dma_new,
@@ -2405,6 +2405,7 @@ nv140_chipset = {
.fb = gv100_fb_new,
.fuse = gm107_fuse_new,
.gpio = gk104_gpio_new,
+ .gsp = gv100_gsp_new,
.i2c = gm200_i2c_new,
.ibus = gm200_ibus_new,
.imem = nv50_instmem_new,
@@ -2435,67 +2436,108 @@ nv140_chipset = {
};
static const struct nvkm_device_chip
+nv162_chipset = {
+ .name = "TU102",
+ .bar = tu102_bar_new,
+ .bios = nvkm_bios_new,
+ .bus = gf100_bus_new,
+ .devinit = tu102_devinit_new,
+ .fault = tu102_fault_new,
+ .fb = gv100_fb_new,
+ .fuse = gm107_fuse_new,
+ .gpio = gk104_gpio_new,
+ .gsp = gv100_gsp_new,
+ .i2c = gm200_i2c_new,
+ .ibus = gm200_ibus_new,
+ .imem = nv50_instmem_new,
+ .ltc = gp102_ltc_new,
+ .mc = tu102_mc_new,
+ .mmu = tu102_mmu_new,
+ .pci = gp100_pci_new,
+ .pmu = gp102_pmu_new,
+ .therm = gp100_therm_new,
+ .timer = gk20a_timer_new,
+ .top = gk104_top_new,
+ .ce[0] = tu102_ce_new,
+ .ce[1] = tu102_ce_new,
+ .ce[2] = tu102_ce_new,
+ .ce[3] = tu102_ce_new,
+ .ce[4] = tu102_ce_new,
+ .disp = tu102_disp_new,
+ .dma = gv100_dma_new,
+ .fifo = tu102_fifo_new,
+ .nvdec[0] = gp102_nvdec_new,
+ .sec2 = tu102_sec2_new,
+};
+
+static const struct nvkm_device_chip
nv164_chipset = {
.name = "TU104",
- .bar = tu104_bar_new,
+ .bar = tu102_bar_new,
.bios = nvkm_bios_new,
.bus = gf100_bus_new,
- .devinit = tu104_devinit_new,
- .fault = tu104_fault_new,
+ .devinit = tu102_devinit_new,
+ .fault = tu102_fault_new,
.fb = gv100_fb_new,
.fuse = gm107_fuse_new,
.gpio = gk104_gpio_new,
+ .gsp = gv100_gsp_new,
.i2c = gm200_i2c_new,
.ibus = gm200_ibus_new,
.imem = nv50_instmem_new,
.ltc = gp102_ltc_new,
- .mc = tu104_mc_new,
- .mmu = tu104_mmu_new,
+ .mc = tu102_mc_new,
+ .mmu = tu102_mmu_new,
.pci = gp100_pci_new,
.pmu = gp102_pmu_new,
.therm = gp100_therm_new,
.timer = gk20a_timer_new,
.top = gk104_top_new,
- .ce[0] = tu104_ce_new,
- .ce[1] = tu104_ce_new,
- .ce[2] = tu104_ce_new,
- .ce[3] = tu104_ce_new,
- .ce[4] = tu104_ce_new,
- .disp = tu104_disp_new,
+ .ce[0] = tu102_ce_new,
+ .ce[1] = tu102_ce_new,
+ .ce[2] = tu102_ce_new,
+ .ce[3] = tu102_ce_new,
+ .ce[4] = tu102_ce_new,
+ .disp = tu102_disp_new,
.dma = gv100_dma_new,
- .fifo = tu104_fifo_new,
+ .fifo = tu102_fifo_new,
+ .nvdec[0] = gp102_nvdec_new,
+ .sec2 = tu102_sec2_new,
};
static const struct nvkm_device_chip
nv166_chipset = {
.name = "TU106",
- .bar = tu104_bar_new,
+ .bar = tu102_bar_new,
.bios = nvkm_bios_new,
.bus = gf100_bus_new,
- .devinit = tu104_devinit_new,
- .fault = tu104_fault_new,
+ .devinit = tu102_devinit_new,
+ .fault = tu102_fault_new,
.fb = gv100_fb_new,
.fuse = gm107_fuse_new,
.gpio = gk104_gpio_new,
+ .gsp = gv100_gsp_new,
.i2c = gm200_i2c_new,
.ibus = gm200_ibus_new,
.imem = nv50_instmem_new,
.ltc = gp102_ltc_new,
- .mc = tu104_mc_new,
- .mmu = tu104_mmu_new,
+ .mc = tu102_mc_new,
+ .mmu = tu102_mmu_new,
.pci = gp100_pci_new,
.pmu = gp102_pmu_new,
.therm = gp100_therm_new,
.timer = gk20a_timer_new,
.top = gk104_top_new,
- .ce[0] = tu104_ce_new,
- .ce[1] = tu104_ce_new,
- .ce[2] = tu104_ce_new,
- .ce[3] = tu104_ce_new,
- .ce[4] = tu104_ce_new,
- .disp = tu104_disp_new,
+ .ce[0] = tu102_ce_new,
+ .ce[1] = tu102_ce_new,
+ .ce[2] = tu102_ce_new,
+ .ce[3] = tu102_ce_new,
+ .ce[4] = tu102_ce_new,
+ .disp = tu102_disp_new,
.dma = gv100_dma_new,
- .fifo = tu104_fifo_new,
+ .fifo = tu102_fifo_new,
+ .nvdec[0] = gp102_nvdec_new,
+ .sec2 = tu102_sec2_new,
};
static int
@@ -2535,6 +2577,7 @@ nvkm_device_subdev(struct nvkm_device *device, int index)
_(FB , device->fb , &device->fb->subdev);
_(FUSE , device->fuse , &device->fuse->subdev);
_(GPIO , device->gpio , &device->gpio->subdev);
+ _(GSP , device->gsp , &device->gsp->subdev);
_(I2C , device->i2c , &device->i2c->subdev);
_(IBUS , device->ibus , device->ibus);
_(ICCSENSE, device->iccsense, &device->iccsense->subdev);
@@ -2950,6 +2993,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x138: device->chip = &nv138_chipset; break;
case 0x13b: device->chip = &nv13b_chipset; break;
case 0x140: device->chip = &nv140_chipset; break;
+ case 0x162: device->chip = &nv162_chipset; break;
case 0x164: device->chip = &nv164_chipset; break;
case 0x166: device->chip = &nv166_chipset; break;
default:
@@ -3017,6 +3061,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
_(NVKM_SUBDEV_FB , fb);
_(NVKM_SUBDEV_FUSE , fuse);
_(NVKM_SUBDEV_GPIO , gpio);
+ _(NVKM_SUBDEV_GSP , gsp);
_(NVKM_SUBDEV_I2C , i2c);
_(NVKM_SUBDEV_IBUS , ibus);
_(NVKM_SUBDEV_ICCSENSE, iccsense);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
index 253ab914a8ef..2a53e37dfa7a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -12,6 +12,7 @@
#include <subdev/fb.h>
#include <subdev/fuse.h>
#include <subdev/gpio.h>
+#include <subdev/gsp.h>
#include <subdev/i2c.h>
#include <subdev/ibus.h>
#include <subdev/iccsense.h>
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index 092ddc4ffefa..03c6d9aef075 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -365,16 +365,15 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index,
}
if (!sclass) {
- switch (index) {
- case 0: sclass = &nvkm_control_oclass; break;
- case 1:
- if (!device->mmu)
- return -EINVAL;
+ if (index-- == 0)
+ sclass = &nvkm_control_oclass;
+ else if (device->mmu && index-- == 0)
sclass = &device->mmu->user;
- break;
- default:
+ else if (device->fault && index-- == 0)
+ sclass = &device->fault->user;
+ else
return -EINVAL;
- }
+
oclass->base = sclass->base;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
index c6a257ba4347..2c28a5e747cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -15,7 +15,7 @@ nvkm-y += nvkm/engine/disp/gm200.o
nvkm-y += nvkm/engine/disp/gp100.o
nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/gv100.o
-nvkm-y += nvkm/engine/disp/tu104.o
+nvkm-y += nvkm/engine/disp/tu102.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/head.o
@@ -39,7 +39,7 @@ nvkm-y += nvkm/engine/disp/sorgk104.o
nvkm-y += nvkm/engine/disp/sorgm107.o
nvkm-y += nvkm/engine/disp/sorgm200.o
nvkm-y += nvkm/engine/disp/sorgv100.o
-nvkm-y += nvkm/engine/disp/sortu104.o
+nvkm-y += nvkm/engine/disp/sortu102.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/dp.o
@@ -71,7 +71,7 @@ nvkm-y += nvkm/engine/disp/rootgm200.o
nvkm-y += nvkm/engine/disp/rootgp100.o
nvkm-y += nvkm/engine/disp/rootgp102.o
nvkm-y += nvkm/engine/disp/rootgv100.o
-nvkm-y += nvkm/engine/disp/roottu104.o
+nvkm-y += nvkm/engine/disp/roottu102.o
nvkm-y += nvkm/engine/disp/channv50.o
nvkm-y += nvkm/engine/disp/changf119.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 794e90982641..e675d9b9d5d7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -91,15 +91,21 @@ gf119_disp_intr_error(struct nv50_disp *disp, int chid)
{
struct nvkm_subdev *subdev = &disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
- u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12));
+ u32 stat = nvkm_rd32(device, 0x6101f0 + (chid * 12));
+ u32 type = (stat & 0x00007000) >> 12;
+ u32 mthd = (stat & 0x00000ffc);
u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12));
- u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12));
+ u32 code = nvkm_rd32(device, 0x6101f8 + (chid * 12));
+ const struct nvkm_enum *reason =
+ nvkm_enum_find(nv50_disp_intr_error_type, type);
- nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n",
- chid, (mthd & 0x0000ffc), data, mthd, unkn);
+ nvkm_error(subdev, "chid %d stat %08x reason %d [%s] mthd %04x "
+ "data %08x code %08x\n",
+ chid, stat, type, reason ? reason->name : "",
+ mthd, data, code);
if (chid < ARRAY_SIZE(disp->chan)) {
- switch (mthd & 0xffc) {
+ switch (mthd) {
case 0x0080:
nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
index 47be0ba4aebe..892be6c9b76c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
@@ -103,10 +103,13 @@ gv100_disp_exception(struct nv50_disp *disp, int chid)
u32 mthd = (stat & 0x00000fff) << 2;
u32 data = nvkm_rd32(device, 0x611024 + (chid * 12));
u32 code = nvkm_rd32(device, 0x611028 + (chid * 12));
+ const struct nvkm_enum *reason =
+ nvkm_enum_find(nv50_disp_intr_error_type, type);
- nvkm_error(subdev, "chid %d %08x [type %d mthd %04x] "
+ nvkm_error(subdev, "chid %d stat %08x reason %d [%s] mthd %04x "
"data %08x code %08x\n",
- chid, stat, type, mthd, data, code);
+ chid, stat, type, reason ? reason->name : "",
+ mthd, data, code);
if (chid < ARRAY_SIZE(disp->chan) && disp->chan[chid]) {
switch (mthd) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
index 790e42f460fd..1681ddccd298 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -201,5 +201,5 @@ int gm200_sor_new(struct nvkm_disp *, int);
int gv100_sor_cnt(struct nvkm_disp *, unsigned long *);
int gv100_sor_new(struct nvkm_disp *, int);
-int tu104_sor_new(struct nvkm_disp *, int);
+int tu102_sor_new(struct nvkm_disp *, int);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index def005dd5fda..e21556bf2cb1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -28,7 +28,6 @@
#include "rootnv50.h"
#include <core/client.h>
-#include <core/enum.h>
#include <core/ramht.h>
#include <subdev/bios.h>
#include <subdev/bios/disp.h>
@@ -593,12 +592,15 @@ nv50_disp_super(struct work_struct *work)
nvkm_wr32(device, 0x610030, 0x80000000);
}
-static const struct nvkm_enum
+const struct nvkm_enum
nv50_disp_intr_error_type[] = {
- { 3, "ILLEGAL_MTHD" },
- { 4, "INVALID_VALUE" },
+ { 0, "NONE" },
+ { 1, "PUSHBUFFER_ERR" },
+ { 2, "TRAP" },
+ { 3, "RESERVED_METHOD" },
+ { 4, "INVALID_ARG" },
{ 5, "INVALID_STATE" },
- { 7, "INVALID_HANDLE" },
+ { 7, "UNRESOLVABLE_HANDLE" },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
index c36a8a7cafa1..e5d00f478bb1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -5,6 +5,8 @@
#include "priv.h"
struct nvkm_head;
+#include <core/enum.h>
+
struct nv50_disp {
const struct nv50_disp_func *func;
struct nvkm_disp base;
@@ -71,6 +73,7 @@ int nv50_disp_init(struct nv50_disp *);
void nv50_disp_fini(struct nv50_disp *);
void nv50_disp_intr(struct nv50_disp *);
void nv50_disp_super(struct work_struct *);
+extern const struct nvkm_enum nv50_disp_intr_error_type[];
int gf119_disp_init(struct nv50_disp *);
void gf119_disp_fini(struct nv50_disp *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h
index 97de928cbde1..aee9822a7a87 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h
@@ -37,5 +37,5 @@ extern const struct nvkm_disp_oclass gm200_disp_root_oclass;
extern const struct nvkm_disp_oclass gp100_disp_root_oclass;
extern const struct nvkm_disp_oclass gp102_disp_root_oclass;
extern const struct nvkm_disp_oclass gv100_disp_root_oclass;
-extern const struct nvkm_disp_oclass tu104_disp_root_oclass;
+extern const struct nvkm_disp_oclass tu102_disp_root_oclass;
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu102.c
index ad438c62f66c..579a5d02308a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu102.c
@@ -25,28 +25,28 @@
#include <nvif/class.h>
static const struct nv50_disp_root_func
-tu104_disp_root = {
+tu102_disp_root = {
.user = {
- {{0,0,TU104_DISP_CURSOR }, gv100_disp_curs_new },
- {{0,0,TU104_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
- {{0,0,TU104_DISP_CORE_CHANNEL_DMA }, gv100_disp_core_new },
- {{0,0,TU104_DISP_WINDOW_CHANNEL_DMA }, gv100_disp_wndw_new },
+ {{0,0,TU102_DISP_CURSOR }, gv100_disp_curs_new },
+ {{0,0,TU102_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
+ {{0,0,TU102_DISP_CORE_CHANNEL_DMA }, gv100_disp_core_new },
+ {{0,0,TU102_DISP_WINDOW_CHANNEL_DMA }, gv100_disp_wndw_new },
{}
},
};
static int
-tu104_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
+tu102_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
void *data, u32 size, struct nvkm_object **pobject)
{
- return nv50_disp_root_new_(&tu104_disp_root, disp, oclass,
+ return nv50_disp_root_new_(&tu102_disp_root, disp, oclass,
data, size, pobject);
}
const struct nvkm_disp_oclass
-tu104_disp_root_oclass = {
- .base.oclass = TU104_DISP,
+tu102_disp_root_oclass = {
+ .base.oclass = TU102_DISP,
.base.minver = -1,
.base.maxver = -1,
- .ctor = tu104_disp_root_new,
+ .ctor = tu102_disp_root_new,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu102.c
index df026a525ef1..d57b73ada89e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu102.c
@@ -24,7 +24,7 @@
#include <subdev/timer.h>
static void
-tu104_sor_dp_vcpi(struct nvkm_ior *sor, int head,
+tu102_sor_dp_vcpi(struct nvkm_ior *sor, int head,
u8 slot, u8 slot_nr, u16 pbn, u16 aligned)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
@@ -35,7 +35,7 @@ tu104_sor_dp_vcpi(struct nvkm_ior *sor, int head,
}
static int
-tu104_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
+tu102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
@@ -62,7 +62,7 @@ tu104_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
}
static const struct nvkm_ior_func
-tu104_sor = {
+tu102_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
@@ -75,11 +75,11 @@ tu104_sor = {
},
.dp = {
.lanes = { 0, 1, 2, 3 },
- .links = tu104_sor_dp_links,
+ .links = tu102_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
- .vcpi = tu104_sor_dp_vcpi,
+ .vcpi = tu102_sor_dp_vcpi,
.audio = gv100_sor_dp_audio,
.audio_sym = gv100_sor_dp_audio_sym,
.watermark = gv100_sor_dp_watermark,
@@ -91,7 +91,7 @@ tu104_sor = {
};
int
-tu104_sor_new(struct nvkm_disp *disp, int id)
+tu102_sor_new(struct nvkm_disp *disp, int id)
{
- return nvkm_ior_new_(&tu104_sor, disp, SOR, id);
+ return nvkm_ior_new_(&tu102_sor, disp, SOR, id);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
index 13fa21459d38..883ae4151ff8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
@@ -29,7 +29,7 @@
#include <subdev/timer.h>
static int
-tu104_disp_init(struct nv50_disp *disp)
+tu102_disp_init(struct nv50_disp *disp)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
struct nvkm_head *head;
@@ -132,21 +132,21 @@ tu104_disp_init(struct nv50_disp *disp)
}
static const struct nv50_disp_func
-tu104_disp = {
- .init = tu104_disp_init,
+tu102_disp = {
+ .init = tu102_disp_init,
.fini = gv100_disp_fini,
.intr = gv100_disp_intr,
.uevent = &gv100_disp_chan_uevent,
.super = gv100_disp_super,
- .root = &tu104_disp_root_oclass,
+ .root = &tu102_disp_root_oclass,
.wndw = { .cnt = gv100_disp_wndw_cnt },
.head = { .cnt = gv100_head_cnt, .new = gv100_head_new },
- .sor = { .cnt = gv100_sor_cnt, .new = tu104_sor_new },
+ .sor = { .cnt = gv100_sor_cnt, .new = tu102_sor_new },
.ramht_size = 0x2000,
};
int
-tu104_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
+tu102_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
{
- return nv50_disp_new_(&tu104_disp, device, index, pdisp);
+ return nv50_disp_new_(&tu102_disp, device, index, pdisp);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
index 816ccaedfc73..8675613e142b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
@@ -22,6 +22,7 @@
#include <engine/falcon.h>
#include <core/gpuobj.h>
+#include <subdev/mc.h>
#include <subdev/timer.h>
#include <engine/fifo.h>
@@ -107,8 +108,10 @@ nvkm_falcon_fini(struct nvkm_engine *engine, bool suspend)
}
}
- nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000);
- nvkm_wr32(device, base + 0x014, 0xffffffff);
+ if (nvkm_mc_enabled(device, engine->subdev.index)) {
+ nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000);
+ nvkm_wr32(device, base + 0x014, 0xffffffff);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
index 87d8e054e40a..05aada541ea5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
@@ -16,7 +16,7 @@ nvkm-y += nvkm/engine/fifo/gm20b.o
nvkm-y += nvkm/engine/fifo/gp100.o
nvkm-y += nvkm/engine/fifo/gp10b.o
nvkm-y += nvkm/engine/fifo/gv100.o
-nvkm-y += nvkm/engine/fifo/tu104.o
+nvkm-y += nvkm/engine/fifo/tu102.o
nvkm-y += nvkm/engine/fifo/chan.o
nvkm-y += nvkm/engine/fifo/channv50.o
@@ -34,7 +34,7 @@ nvkm-y += nvkm/engine/fifo/gpfifog84.o
nvkm-y += nvkm/engine/fifo/gpfifogf100.o
nvkm-y += nvkm/engine/fifo/gpfifogk104.o
nvkm-y += nvkm/engine/fifo/gpfifogv100.o
-nvkm-y += nvkm/engine/fifo/gpfifotu104.o
+nvkm-y += nvkm/engine/fifo/gpfifotu102.o
nvkm-y += nvkm/engine/fifo/usergv100.o
-nvkm-y += nvkm/engine/fifo/usertu104.o
+nvkm-y += nvkm/engine/fifo/usertu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
index a14545d871d8..f8557cdfbd81 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
@@ -47,6 +47,6 @@ int gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *,
int gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *,
struct nvkm_engine *, bool);
-int tu104_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
+int tu102_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
void *data, u32 size, struct nvkm_object **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c
index ff70484dd01a..abef7fb6e2d3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c
@@ -29,14 +29,14 @@
#include <nvif/unpack.h>
static u32
-tu104_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *base)
+tu102_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *base)
{
struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
return (chan->runl << 16) | chan->base.chid;
}
static const struct nvkm_fifo_chan_func
-tu104_fifo_gpfifo = {
+tu102_fifo_gpfifo = {
.dtor = gk104_fifo_gpfifo_dtor,
.init = gk104_fifo_gpfifo_init,
.fini = gk104_fifo_gpfifo_fini,
@@ -45,11 +45,11 @@ tu104_fifo_gpfifo = {
.engine_dtor = gk104_fifo_gpfifo_engine_dtor,
.engine_init = gv100_fifo_gpfifo_engine_init,
.engine_fini = gv100_fifo_gpfifo_engine_fini,
- .submit_token = tu104_fifo_gpfifo_submit_token,
+ .submit_token = tu102_fifo_gpfifo_submit_token,
};
int
-tu104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
+tu102_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
void *data, u32 size, struct nvkm_object **pobject)
{
struct nvkm_object *parent = oclass->parent;
@@ -67,7 +67,7 @@ tu104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
args->v0.ilength, args->v0.runlist, args->v0.priv);
if (args->v0.priv && !oclass->client->super)
return -EINVAL;
- return gv100_fifo_gpfifo_new_(&tu104_fifo_gpfifo, fifo,
+ return gv100_fifo_gpfifo_new_(&tu102_fifo_gpfifo, fifo,
&args->v0.runlist,
&args->v0.chid,
args->v0.vmm,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
index 98c80705bc61..005f3e1729b9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
@@ -29,7 +29,7 @@
#include <nvif/class.h>
static void
-tu104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
+tu102_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
struct nvkm_memory *mem, int nr)
{
struct nvkm_device *device = fifo->base.engine.subdev.device;
@@ -44,15 +44,15 @@ tu104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
}
const struct gk104_fifo_runlist_func
-tu104_fifo_runlist = {
+tu102_fifo_runlist = {
.size = 16,
.cgrp = gv100_fifo_runlist_cgrp,
.chan = gv100_fifo_runlist_chan,
- .commit = tu104_fifo_runlist_commit,
+ .commit = tu102_fifo_runlist_commit,
};
static const struct nvkm_enum
-tu104_fifo_fault_engine[] = {
+tu102_fifo_fault_engine[] = {
{ 0x01, "DISPLAY" },
{ 0x03, "PTP" },
{ 0x06, "PWR_PMU" },
@@ -80,7 +80,7 @@ tu104_fifo_fault_engine[] = {
};
static void
-tu104_fifo_pbdma_init(struct gk104_fifo *fifo)
+tu102_fifo_pbdma_init(struct gk104_fifo *fifo)
{
struct nvkm_device *device = fifo->base.engine.subdev.device;
const u32 mask = (1 << fifo->pbdma_nr) - 1;
@@ -89,28 +89,28 @@ tu104_fifo_pbdma_init(struct gk104_fifo *fifo)
}
static const struct gk104_fifo_pbdma_func
-tu104_fifo_pbdma = {
+tu102_fifo_pbdma = {
.nr = gm200_fifo_pbdma_nr,
- .init = tu104_fifo_pbdma_init,
+ .init = tu102_fifo_pbdma_init,
.init_timeout = gk208_fifo_pbdma_init_timeout,
};
static const struct gk104_fifo_func
-tu104_fifo = {
- .pbdma = &tu104_fifo_pbdma,
+tu102_fifo = {
+ .pbdma = &tu102_fifo_pbdma,
.fault.access = gv100_fifo_fault_access,
- .fault.engine = tu104_fifo_fault_engine,
+ .fault.engine = tu102_fifo_fault_engine,
.fault.reason = gv100_fifo_fault_reason,
.fault.hubclient = gv100_fifo_fault_hubclient,
.fault.gpcclient = gv100_fifo_fault_gpcclient,
- .runlist = &tu104_fifo_runlist,
- .user = {{-1,-1,VOLTA_USERMODE_A }, tu104_fifo_user_new },
- .chan = {{ 0, 0,TURING_CHANNEL_GPFIFO_A}, tu104_fifo_gpfifo_new },
+ .runlist = &tu102_fifo_runlist,
+ .user = {{-1,-1,VOLTA_USERMODE_A }, tu102_fifo_user_new },
+ .chan = {{ 0, 0,TURING_CHANNEL_GPFIFO_A}, tu102_fifo_gpfifo_new },
.cgrp_force = true,
};
int
-tu104_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo)
+tu102_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo)
{
- return gk104_fifo_new_(&tu104_fifo, device, index, 4096, pfifo);
+ return gk104_fifo_new_(&tu102_fifo, device, index, 4096, pfifo);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
index 14b0c6bde8eb..54a3a3092cc0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
@@ -3,6 +3,6 @@
#include "priv.h"
int gv100_fifo_user_new(const struct nvkm_oclass *, void *, u32,
struct nvkm_object **);
-int tu104_fifo_user_new(const struct nvkm_oclass *, void *, u32,
+int tu102_fifo_user_new(const struct nvkm_oclass *, void *, u32,
struct nvkm_object **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c
index 8f98548a21f6..217268f8ccad 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c
@@ -22,7 +22,7 @@
#include "user.h"
static int
-tu104_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
+tu102_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
struct nvkm_device *device = object->engine->subdev.device;
@@ -33,13 +33,13 @@ tu104_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
}
static const struct nvkm_object_func
-tu104_fifo_user = {
- .map = tu104_fifo_user_map,
+tu102_fifo_user = {
+ .map = tu102_fifo_user_map,
};
int
-tu104_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+tu102_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
- return nvkm_object_new_(&tu104_fifo_user, oclass, argv, argc, pobject);
+ return nvkm_object_new_(&tu102_fifo_user, oclass, argv, argc, pobject);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
index cd8cf6f7024c..d41fb94524e9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
@@ -25,6 +25,33 @@
#include <engine/fifo.h>
+u32
+nvkm_gr_ctxsw_inst(struct nvkm_device *device)
+{
+ struct nvkm_gr *gr = device->gr;
+ if (gr && gr->func->ctxsw.inst)
+ return gr->func->ctxsw.inst(gr);
+ return 0;
+}
+
+int
+nvkm_gr_ctxsw_resume(struct nvkm_device *device)
+{
+ struct nvkm_gr *gr = device->gr;
+ if (gr && gr->func->ctxsw.resume)
+ return gr->func->ctxsw.resume(gr);
+ return 0;
+}
+
+int
+nvkm_gr_ctxsw_pause(struct nvkm_device *device)
+{
+ struct nvkm_gr *gr = device->gr;
+ if (gr && gr->func->ctxsw.pause)
+ return gr->func->ctxsw.pause(gr);
+ return 0;
+}
+
static bool
nvkm_gr_chsw_load(struct nvkm_engine *engine)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
index e813a3f8ea93..85f2d1e950e8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
@@ -1523,13 +1523,9 @@ gf100_grctx_generate(struct gf100_gr *gr)
/* Make channel current. */
addr = nvkm_memory_addr(inst) >> 12;
if (gr->firmware) {
- nvkm_wr32(device, 0x409840, 0x00000030);
- nvkm_wr32(device, 0x409500, 0x80000000 | addr);
- nvkm_wr32(device, 0x409504, 0x00000003);
- nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800) & 0x00000010)
- break;
- );
+ ret = gf100_gr_fecs_bind_pointer(gr, 0x80000000 | addr);
+ if (ret)
+ goto done;
nvkm_kmap(data);
nvkm_wo32(data, 0x1c, 1);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index 70d3d41e616c..81a13cf9a292 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -715,6 +715,211 @@ gf100_gr_pack_mmio[] = {
* PGRAPH engine/subdev functions
******************************************************************************/
+static u32
+gf100_gr_ctxsw_inst(struct nvkm_gr *gr)
+{
+ return nvkm_rd32(gr->engine.subdev.device, 0x409b00);
+}
+
+static int
+gf100_gr_fecs_ctrl_ctxsw(struct gf100_gr *gr, u32 mthd)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409804, 0xffffffff);
+ nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409500, 0xffffffff);
+ nvkm_wr32(device, 0x409504, mthd);
+ nvkm_msec(device, 2000,
+ u32 stat = nvkm_rd32(device, 0x409804);
+ if (stat == 0x00000002)
+ return -EIO;
+ if (stat == 0x00000001)
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+int
+gf100_gr_fecs_start_ctxsw(struct nvkm_gr *base)
+{
+ struct gf100_gr *gr = gf100_gr(base);
+ int ret = 0;
+
+ mutex_lock(&gr->fecs.mutex);
+ if (!--gr->fecs.disable) {
+ if (WARN_ON(ret = gf100_gr_fecs_ctrl_ctxsw(gr, 0x39)))
+ gr->fecs.disable++;
+ }
+ mutex_unlock(&gr->fecs.mutex);
+ return ret;
+}
+
+int
+gf100_gr_fecs_stop_ctxsw(struct nvkm_gr *base)
+{
+ struct gf100_gr *gr = gf100_gr(base);
+ int ret = 0;
+
+ mutex_lock(&gr->fecs.mutex);
+ if (!gr->fecs.disable++) {
+ if (WARN_ON(ret = gf100_gr_fecs_ctrl_ctxsw(gr, 0x38)))
+ gr->fecs.disable--;
+ }
+ mutex_unlock(&gr->fecs.mutex);
+ return ret;
+}
+
+int
+gf100_gr_fecs_bind_pointer(struct gf100_gr *gr, u32 inst)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409840, 0x00000030);
+ nvkm_wr32(device, 0x409500, inst);
+ nvkm_wr32(device, 0x409504, 0x00000003);
+ nvkm_msec(device, 2000,
+ u32 stat = nvkm_rd32(device, 0x409800);
+ if (stat & 0x00000020)
+ return -EIO;
+ if (stat & 0x00000010)
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_set_reglist_virtual_address(struct gf100_gr *gr, u64 addr)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409810, addr >> 8);
+ nvkm_wr32(device, 0x409800, 0x00000000);
+ nvkm_wr32(device, 0x409500, 0x00000001);
+ nvkm_wr32(device, 0x409504, 0x00000032);
+ nvkm_msec(device, 2000,
+ if (nvkm_rd32(device, 0x409800) == 0x00000001)
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_set_reglist_bind_instance(struct gf100_gr *gr, u32 inst)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409810, inst);
+ nvkm_wr32(device, 0x409800, 0x00000000);
+ nvkm_wr32(device, 0x409500, 0x00000001);
+ nvkm_wr32(device, 0x409504, 0x00000031);
+ nvkm_msec(device, 2000,
+ if (nvkm_rd32(device, 0x409800) == 0x00000001)
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_discover_reglist_image_size(struct gf100_gr *gr, u32 *psize)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409800, 0x00000000);
+ nvkm_wr32(device, 0x409500, 0x00000001);
+ nvkm_wr32(device, 0x409504, 0x00000030);
+ nvkm_msec(device, 2000,
+ if ((*psize = nvkm_rd32(device, 0x409800)))
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_elpg_bind(struct gf100_gr *gr)
+{
+ u32 size;
+ int ret;
+
+ ret = gf100_gr_fecs_discover_reglist_image_size(gr, &size);
+ if (ret)
+ return ret;
+
+ /*XXX: We need to allocate + map the above into PMU's inst block,
+ * which which means we probably need a proper PMU before we
+ * even bother.
+ */
+
+ ret = gf100_gr_fecs_set_reglist_bind_instance(gr, 0);
+ if (ret)
+ return ret;
+
+ return gf100_gr_fecs_set_reglist_virtual_address(gr, 0);
+}
+
+static int
+gf100_gr_fecs_discover_pm_image_size(struct gf100_gr *gr, u32 *psize)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409500, 0x00000000);
+ nvkm_wr32(device, 0x409504, 0x00000025);
+ nvkm_msec(device, 2000,
+ if ((*psize = nvkm_rd32(device, 0x409800)))
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_discover_zcull_image_size(struct gf100_gr *gr, u32 *psize)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409500, 0x00000000);
+ nvkm_wr32(device, 0x409504, 0x00000016);
+ nvkm_msec(device, 2000,
+ if ((*psize = nvkm_rd32(device, 0x409800)))
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static int
+gf100_gr_fecs_discover_image_size(struct gf100_gr *gr, u32 *psize)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409500, 0x00000000);
+ nvkm_wr32(device, 0x409504, 0x00000010);
+ nvkm_msec(device, 2000,
+ if ((*psize = nvkm_rd32(device, 0x409800)))
+ return 0;
+ );
+
+ return -ETIMEDOUT;
+}
+
+static void
+gf100_gr_fecs_set_watchdog_timeout(struct gf100_gr *gr, u32 timeout)
+{
+ struct nvkm_device *device = gr->base.engine.subdev.device;
+
+ nvkm_wr32(device, 0x409840, 0xffffffff);
+ nvkm_wr32(device, 0x409500, timeout);
+ nvkm_wr32(device, 0x409504, 0x00000021);
+}
+
static bool
gf100_gr_chsw_load(struct nvkm_gr *base)
{
@@ -1487,6 +1692,7 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
struct nvkm_device *device = subdev->device;
struct nvkm_secboot *sb = device->secboot;
u32 secboot_mask = 0;
+ int ret;
/* load fuc microcode */
nvkm_mc_unk260(device, 0);
@@ -1495,12 +1701,12 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS))
secboot_mask |= BIT(NVKM_SECBOOT_FALCON_FECS);
else
- gf100_gr_init_fw(gr->fecs, &gr->fuc409c, &gr->fuc409d);
+ gf100_gr_init_fw(gr->fecs.falcon, &gr->fuc409c, &gr->fuc409d);
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS))
secboot_mask |= BIT(NVKM_SECBOOT_FALCON_GPCCS);
else
- gf100_gr_init_fw(gr->gpccs, &gr->fuc41ac, &gr->fuc41ad);
+ gf100_gr_init_fw(gr->gpccs.falcon, &gr->fuc41ac, &gr->fuc41ad);
if (secboot_mask != 0) {
int ret = nvkm_secboot_reset(sb, secboot_mask);
@@ -1515,8 +1721,8 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
nvkm_wr32(device, 0x41a10c, 0x00000000);
nvkm_wr32(device, 0x40910c, 0x00000000);
- nvkm_falcon_start(gr->gpccs);
- nvkm_falcon_start(gr->fecs);
+ nvkm_falcon_start(gr->gpccs.falcon);
+ nvkm_falcon_start(gr->fecs.falcon);
if (nvkm_msec(device, 2000,
if (nvkm_rd32(device, 0x409800) & 0x00000001)
@@ -1524,72 +1730,36 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
) < 0)
return -EBUSY;
- nvkm_wr32(device, 0x409840, 0xffffffff);
- nvkm_wr32(device, 0x409500, 0x7fffffff);
- nvkm_wr32(device, 0x409504, 0x00000021);
+ gf100_gr_fecs_set_watchdog_timeout(gr, 0x7fffffff);
- nvkm_wr32(device, 0x409840, 0xffffffff);
- nvkm_wr32(device, 0x409500, 0x00000000);
- nvkm_wr32(device, 0x409504, 0x00000010);
- if (nvkm_msec(device, 2000,
- if ((gr->size = nvkm_rd32(device, 0x409800)))
- break;
- ) < 0)
- return -EBUSY;
-
- nvkm_wr32(device, 0x409840, 0xffffffff);
- nvkm_wr32(device, 0x409500, 0x00000000);
- nvkm_wr32(device, 0x409504, 0x00000016);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800))
- break;
- ) < 0)
- return -EBUSY;
+ /* Determine how much memory is required to store main context image. */
+ ret = gf100_gr_fecs_discover_image_size(gr, &gr->size);
+ if (ret)
+ return ret;
- nvkm_wr32(device, 0x409840, 0xffffffff);
- nvkm_wr32(device, 0x409500, 0x00000000);
- nvkm_wr32(device, 0x409504, 0x00000025);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800))
- break;
- ) < 0)
- return -EBUSY;
+ /* Determine how much memory is required to store ZCULL image. */
+ ret = gf100_gr_fecs_discover_zcull_image_size(gr, &gr->size_zcull);
+ if (ret)
+ return ret;
- if (device->chipset >= 0xe0) {
- nvkm_wr32(device, 0x409800, 0x00000000);
- nvkm_wr32(device, 0x409500, 0x00000001);
- nvkm_wr32(device, 0x409504, 0x00000030);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800))
- break;
- ) < 0)
- return -EBUSY;
-
- nvkm_wr32(device, 0x409810, 0xb00095c8);
- nvkm_wr32(device, 0x409800, 0x00000000);
- nvkm_wr32(device, 0x409500, 0x00000001);
- nvkm_wr32(device, 0x409504, 0x00000031);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800))
- break;
- ) < 0)
- return -EBUSY;
-
- nvkm_wr32(device, 0x409810, 0x00080420);
- nvkm_wr32(device, 0x409800, 0x00000000);
- nvkm_wr32(device, 0x409500, 0x00000001);
- nvkm_wr32(device, 0x409504, 0x00000032);
- if (nvkm_msec(device, 2000,
- if (nvkm_rd32(device, 0x409800))
- break;
- ) < 0)
- return -EBUSY;
+ /* Determine how much memory is required to store PerfMon image. */
+ ret = gf100_gr_fecs_discover_pm_image_size(gr, &gr->size_pm);
+ if (ret)
+ return ret;
- nvkm_wr32(device, 0x409614, 0x00000070);
- nvkm_wr32(device, 0x409614, 0x00000770);
- nvkm_wr32(device, 0x40802c, 0x00000001);
+ /*XXX: We (likely) require PMU support to even bother with this.
+ *
+ * Also, it seems like not all GPUs support ELPG. Traces I
+ * have here show RM enabling it on Kepler/Turing, but none
+ * of the GPUs between those. NVGPU decides this by PCIID.
+ */
+ if (0) {
+ ret = gf100_gr_fecs_elpg_bind(gr);
+ if (ret)
+ return ret;
}
+ /* Generate golden context image. */
if (gr->data == NULL) {
int ret = gf100_grctx_generate(gr);
if (ret) {
@@ -1614,15 +1784,19 @@ gf100_gr_init_ctxctl_int(struct gf100_gr *gr)
/* load HUB microcode */
nvkm_mc_unk260(device, 0);
- nvkm_falcon_load_dmem(gr->fecs, gr->func->fecs.ucode->data.data, 0x0,
+ nvkm_falcon_load_dmem(gr->fecs.falcon,
+ gr->func->fecs.ucode->data.data, 0x0,
gr->func->fecs.ucode->data.size, 0);
- nvkm_falcon_load_imem(gr->fecs, gr->func->fecs.ucode->code.data, 0x0,
+ nvkm_falcon_load_imem(gr->fecs.falcon,
+ gr->func->fecs.ucode->code.data, 0x0,
gr->func->fecs.ucode->code.size, 0, 0, false);
/* load GPC microcode */
- nvkm_falcon_load_dmem(gr->gpccs, gr->func->gpccs.ucode->data.data, 0x0,
+ nvkm_falcon_load_dmem(gr->gpccs.falcon,
+ gr->func->gpccs.ucode->data.data, 0x0,
gr->func->gpccs.ucode->data.size, 0);
- nvkm_falcon_load_imem(gr->gpccs, gr->func->gpccs.ucode->code.data, 0x0,
+ nvkm_falcon_load_imem(gr->gpccs.falcon,
+ gr->func->gpccs.ucode->code.data, 0x0,
gr->func->gpccs.ucode->code.size, 0, 0, false);
nvkm_mc_unk260(device, 1);
@@ -1769,11 +1943,13 @@ gf100_gr_oneinit(struct nvkm_gr *base)
int i, j;
int ret;
- ret = nvkm_falcon_v1_new(subdev, "FECS", 0x409000, &gr->fecs);
+ ret = nvkm_falcon_v1_new(subdev, "FECS", 0x409000, &gr->fecs.falcon);
if (ret)
return ret;
- ret = nvkm_falcon_v1_new(subdev, "GPCCS", 0x41a000, &gr->gpccs);
+ mutex_init(&gr->fecs.mutex);
+
+ ret = nvkm_falcon_v1_new(subdev, "GPCCS", 0x41a000, &gr->gpccs.falcon);
if (ret)
return ret;
@@ -1816,11 +1992,11 @@ gf100_gr_init_(struct nvkm_gr *base)
nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false);
- ret = nvkm_falcon_get(gr->fecs, subdev);
+ ret = nvkm_falcon_get(gr->fecs.falcon, subdev);
if (ret)
return ret;
- ret = nvkm_falcon_get(gr->gpccs, subdev);
+ ret = nvkm_falcon_get(gr->gpccs.falcon, subdev);
if (ret)
return ret;
@@ -1832,8 +2008,8 @@ gf100_gr_fini_(struct nvkm_gr *base, bool suspend)
{
struct gf100_gr *gr = gf100_gr(base);
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
- nvkm_falcon_put(gr->gpccs, subdev);
- nvkm_falcon_put(gr->fecs, subdev);
+ nvkm_falcon_put(gr->gpccs.falcon, subdev);
+ nvkm_falcon_put(gr->fecs.falcon, subdev);
return 0;
}
@@ -1859,8 +2035,8 @@ gf100_gr_dtor(struct nvkm_gr *base)
gr->func->dtor(gr);
kfree(gr->data);
- nvkm_falcon_del(&gr->gpccs);
- nvkm_falcon_del(&gr->fecs);
+ nvkm_falcon_del(&gr->gpccs.falcon);
+ nvkm_falcon_del(&gr->fecs.falcon);
gf100_gr_dtor_fw(&gr->fuc409c);
gf100_gr_dtor_fw(&gr->fuc409d);
@@ -1886,6 +2062,9 @@ gf100_gr_ = {
.chan_new = gf100_gr_chan_new,
.object_get = gf100_gr_object_get,
.chsw_load = gf100_gr_chsw_load,
+ .ctxsw.pause = gf100_gr_fecs_stop_ctxsw,
+ .ctxsw.resume = gf100_gr_fecs_start_ctxsw,
+ .ctxsw.inst = gf100_gr_ctxsw_inst,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
index dc46cf0131db..fafdd0bbea9b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -82,8 +82,16 @@ struct gf100_gr {
const struct gf100_gr_func *func;
struct nvkm_gr base;
- struct nvkm_falcon *fecs;
- struct nvkm_falcon *gpccs;
+ struct {
+ struct nvkm_falcon *falcon;
+ struct mutex mutex;
+ u32 disable;
+ } fecs;
+
+ struct {
+ struct nvkm_falcon *falcon;
+ } gpccs;
+
struct gf100_gr_fuc fuc409c;
struct gf100_gr_fuc fuc409d;
struct gf100_gr_fuc fuc41ac;
@@ -128,6 +136,8 @@ struct gf100_gr {
struct gf100_gr_mmio mmio_list[4096/8];
u32 size;
u32 *data;
+ u32 size_zcull;
+ u32 size_pm;
};
int gf100_gr_ctor(const struct gf100_gr_func *, struct nvkm_device *,
@@ -136,6 +146,8 @@ int gf100_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
int, struct nvkm_gr **);
void *gf100_gr_dtor(struct nvkm_gr *);
+int gf100_gr_fecs_bind_pointer(struct gf100_gr *, u32 inst);
+
struct gf100_gr_func_zbc {
void (*clear_color)(struct gf100_gr *, int zbc);
void (*clear_depth)(struct gf100_gr *, int zbc);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
index 66359c23cbce..d4d5601c51e7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
@@ -27,6 +27,11 @@ struct nvkm_gr_func {
*/
u64 (*units)(struct nvkm_gr *);
bool (*chsw_load)(struct nvkm_gr *);
+ struct {
+ int (*pause)(struct nvkm_gr *);
+ int (*resume)(struct nvkm_gr *);
+ u32 (*inst)(struct nvkm_gr *);
+ } ctxsw;
struct nvkm_sclass sclass[];
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
index 4807021fd990..4a63581bdd5e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c
@@ -21,13 +21,21 @@
*/
#include "priv.h"
+#include <subdev/top.h>
#include <engine/falcon.h>
static int
nvkm_nvdec_oneinit(struct nvkm_engine *engine)
{
struct nvkm_nvdec *nvdec = nvkm_nvdec(engine);
- return nvkm_falcon_v1_new(&nvdec->engine.subdev, "NVDEC", 0x84000,
+ struct nvkm_subdev *subdev = &nvdec->engine.subdev;
+
+ nvdec->addr = nvkm_top_addr(subdev->device, subdev->index);
+ if (!nvdec->addr)
+ return -EINVAL;
+
+ /*XXX: fix naming of this when adding support for multiple-NVDEC */
+ return nvkm_falcon_v1_new(subdev, "NVDEC", nvdec->addr,
&nvdec->falcon);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
index 4b17254cfbd0..d9cdea7d9353 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
@@ -1,2 +1,3 @@
nvkm-y += nvkm/engine/sec2/base.o
nvkm-y += nvkm/engine/sec2/gp102.o
+nvkm-y += nvkm/engine/sec2/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
index f865d2a3e184..1b49e5b6717f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
@@ -22,6 +22,7 @@
#include "priv.h"
#include <core/msgqueue.h>
+#include <subdev/top.h>
#include <engine/falcon.h>
static void *
@@ -39,18 +40,18 @@ nvkm_sec2_intr(struct nvkm_engine *engine)
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
struct nvkm_subdev *subdev = &engine->subdev;
struct nvkm_device *device = subdev->device;
- u32 disp = nvkm_rd32(device, 0x8701c);
- u32 intr = nvkm_rd32(device, 0x87008) & disp & ~(disp >> 16);
+ u32 disp = nvkm_rd32(device, sec2->addr + 0x01c);
+ u32 intr = nvkm_rd32(device, sec2->addr + 0x008) & disp & ~(disp >> 16);
if (intr & 0x00000040) {
schedule_work(&sec2->work);
- nvkm_wr32(device, 0x87004, 0x00000040);
+ nvkm_wr32(device, sec2->addr + 0x004, 0x00000040);
intr &= ~0x00000040;
}
if (intr) {
nvkm_error(subdev, "unhandled intr %08x\n", intr);
- nvkm_wr32(device, 0x87004, intr);
+ nvkm_wr32(device, sec2->addr + 0x004, intr);
}
}
@@ -74,8 +75,15 @@ static int
nvkm_sec2_oneinit(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
- return nvkm_falcon_v1_new(&sec2->engine.subdev, "SEC2", 0x87000,
- &sec2->falcon);
+ struct nvkm_subdev *subdev = &sec2->engine.subdev;
+
+ if (!sec2->addr) {
+ sec2->addr = nvkm_top_addr(subdev->device, subdev->index);
+ if (WARN_ON(!sec2->addr))
+ return -EINVAL;
+ }
+
+ return nvkm_falcon_v1_new(subdev, "SEC2", sec2->addr, &sec2->falcon);
}
static int
@@ -95,13 +103,14 @@ nvkm_sec2 = {
};
int
-nvkm_sec2_new_(struct nvkm_device *device, int index,
+nvkm_sec2_new_(struct nvkm_device *device, int index, u32 addr,
struct nvkm_sec2 **psec2)
{
struct nvkm_sec2 *sec2;
if (!(sec2 = *psec2 = kzalloc(sizeof(*sec2), GFP_KERNEL)))
return -ENOMEM;
+ sec2->addr = addr;
INIT_WORK(&sec2->work, nvkm_sec2_recv);
return nvkm_engine_ctor(&nvkm_sec2, device, index, true, &sec2->engine);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
index 9be1524c08f5..858cf27fa010 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
@@ -26,5 +26,5 @@ int
gp102_sec2_new(struct nvkm_device *device, int index,
struct nvkm_sec2 **psec2)
{
- return nvkm_sec2_new_(device, index, psec2);
+ return nvkm_sec2_new_(device, index, 0, psec2);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
index 2f97c806a79d..ab0165e2d1a3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
@@ -5,6 +5,5 @@
#define nvkm_sec2(p) container_of((p), struct nvkm_sec2, engine)
-int nvkm_sec2_new_(struct nvkm_device *, int, struct nvkm_sec2 **);
-
+int nvkm_sec2_new_(struct nvkm_device *, int, u32 addr, struct nvkm_sec2 **);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
index b6ac47617c70..d655576164b1 100644
--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
+ * Copyright 2019 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -18,15 +18,16 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
*/
-#ifndef __DAL_I2C_AUX_DCE120_H__
-#define __DAL_I2C_AUX_DCE120_H__
-
-struct i2caux *dal_i2caux_dce120_create(
- struct dc_context *ctx);
+#include "priv.h"
-#endif /* __DAL_I2C_AUX_DCE120_H__ */
+int
+tu102_sec2_new(struct nvkm_device *device, int index,
+ struct nvkm_sec2 **psec2)
+{
+ /* TOP info wasn't updated on Turing to reflect the PRI
+ * address change for some reason. We override it here.
+ */
+ return nvkm_sec2_new_(device, index, 0x840000, psec2);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
index 427340153640..366c87de6e72 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c
@@ -204,6 +204,9 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func,
debug_reg = 0x408;
falcon->has_emem = true;
break;
+ case NVKM_SUBDEV_GSP:
+ debug_reg = 0x0; /*XXX*/
+ break;
default:
nvkm_warn(subdev, "unsupported falcon %s!\n",
nvkm_subdev_name[subdev->index]);
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
index 771e16a16267..a8bee1e046aa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
@@ -269,7 +269,7 @@ cmd_write(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *cmd,
commit = false;
}
- cmd_queue_close(priv, queue, commit);
+ cmd_queue_close(priv, queue, commit);
return ret;
}
@@ -347,7 +347,7 @@ nvkm_msgqueue_post(struct nvkm_msgqueue *priv, enum msgqueue_msg_priority prio,
ret = cmd_write(priv, cmd, queue);
if (ret) {
seq->state = SEQ_STATE_PENDING;
- msgqueue_seq_release(priv, seq);
+ msgqueue_seq_release(priv, seq);
}
return ret;
@@ -373,7 +373,7 @@ msgqueue_msg_handle(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *hdr)
if (seq->completion)
complete(seq->completion);
- msgqueue_seq_release(priv, seq);
+ msgqueue_seq_release(priv, seq);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
index cfdffef1afb9..a339fe03d423 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
@@ -7,6 +7,7 @@ include $(src)/nvkm/subdev/fault/Kbuild
include $(src)/nvkm/subdev/fb/Kbuild
include $(src)/nvkm/subdev/fuse/Kbuild
include $(src)/nvkm/subdev/gpio/Kbuild
+include $(src)/nvkm/subdev/gsp/Kbuild
include $(src)/nvkm/subdev/i2c/Kbuild
include $(src)/nvkm/subdev/ibus/Kbuild
include $(src)/nvkm/subdev/iccsense/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
index ab0282dc0736..dc300600c019 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
@@ -5,4 +5,4 @@ nvkm-y += nvkm/subdev/bar/gf100.o
nvkm-y += nvkm/subdev/bar/gk20a.o
nvkm-y += nvkm/subdev/bar/gm107.o
nvkm-y += nvkm/subdev/bar/gm20b.o
-nvkm-y += nvkm/subdev/bar/tu104.o
+nvkm-y += nvkm/subdev/bar/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c
index ecaead156e9b..798f65ec3a86 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c
@@ -25,7 +25,7 @@
#include <subdev/timer.h>
static void
-tu104_bar_bar2_wait(struct nvkm_bar *bar)
+tu102_bar_bar2_wait(struct nvkm_bar *bar)
{
struct nvkm_device *device = bar->subdev.device;
nvkm_msec(device, 2000,
@@ -35,13 +35,13 @@ tu104_bar_bar2_wait(struct nvkm_bar *bar)
}
static void
-tu104_bar_bar2_fini(struct nvkm_bar *bar)
+tu102_bar_bar2_fini(struct nvkm_bar *bar)
{
nvkm_mask(bar->subdev.device, 0xb80f48, 0x80000000, 0x00000000);
}
static void
-tu104_bar_bar2_init(struct nvkm_bar *base)
+tu102_bar_bar2_init(struct nvkm_bar *base)
{
struct nvkm_device *device = base->subdev.device;
struct gf100_bar *bar = gf100_bar(base);
@@ -52,7 +52,7 @@ tu104_bar_bar2_init(struct nvkm_bar *base)
}
static void
-tu104_bar_bar1_wait(struct nvkm_bar *bar)
+tu102_bar_bar1_wait(struct nvkm_bar *bar)
{
struct nvkm_device *device = bar->subdev.device;
nvkm_msec(device, 2000,
@@ -62,13 +62,13 @@ tu104_bar_bar1_wait(struct nvkm_bar *bar)
}
static void
-tu104_bar_bar1_fini(struct nvkm_bar *bar)
+tu102_bar_bar1_fini(struct nvkm_bar *bar)
{
nvkm_mask(bar->subdev.device, 0xb80f40, 0x80000000, 0x00000000);
}
static void
-tu104_bar_bar1_init(struct nvkm_bar *base)
+tu102_bar_bar1_init(struct nvkm_bar *base)
{
struct nvkm_device *device = base->subdev.device;
struct gf100_bar *bar = gf100_bar(base);
@@ -77,22 +77,22 @@ tu104_bar_bar1_init(struct nvkm_bar *base)
}
static const struct nvkm_bar_func
-tu104_bar = {
+tu102_bar = {
.dtor = gf100_bar_dtor,
.oneinit = gf100_bar_oneinit,
- .bar1.init = tu104_bar_bar1_init,
- .bar1.fini = tu104_bar_bar1_fini,
- .bar1.wait = tu104_bar_bar1_wait,
+ .bar1.init = tu102_bar_bar1_init,
+ .bar1.fini = tu102_bar_bar1_fini,
+ .bar1.wait = tu102_bar_bar1_wait,
.bar1.vmm = gf100_bar_bar1_vmm,
- .bar2.init = tu104_bar_bar2_init,
- .bar2.fini = tu104_bar_bar2_fini,
- .bar2.wait = tu104_bar_bar2_wait,
+ .bar2.init = tu102_bar_bar2_init,
+ .bar2.fini = tu102_bar_bar2_fini,
+ .bar2.wait = tu102_bar_bar2_wait,
.bar2.vmm = gf100_bar_bar2_vmm,
.flush = g84_bar_flush,
};
int
-tu104_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar)
+tu102_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar)
{
- return gf100_bar_new_(&tu104_bar, device, index, pbar);
+ return gf100_bar_new_(&tu102_bar, device, index, pbar);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
index 3133b28f849c..b099d1209be8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
@@ -212,7 +212,7 @@ nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
u16 data;
if (*ver >= 0x30) {
- const u8 vsoff[] = { 0, 4, 7, 9 };
+ static const u8 vsoff[] = { 0, 4, 7, 9 };
idx = (pc * 10) + vsoff[vs] + pe;
if (*ver >= 0x40 && *ver <= 0x41 && *hdr >= 0x12)
idx += nvbios_rd08(bios, outp + 0x11) * 40;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
index 9cc10e438b3d..ec0e9f7224b5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
@@ -806,12 +806,12 @@ init_generic_condition(struct nvbios_init *init)
init->offset += 3;
switch (cond) {
- case 0:
+ case 0: /* CONDITION_ID_INT_DP. */
if (init_conn(init) != DCB_CONNECTOR_eDP)
init_exec_set(init, false);
break;
- case 1:
- case 2:
+ case 1: /* CONDITION_ID_USE_SPPLL0. */
+ case 2: /* CONDITION_ID_USE_SPPLL1. */
if ( init->outp &&
(data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
(init->outp->or << 0) |
@@ -826,10 +826,13 @@ init_generic_condition(struct nvbios_init *init)
if (init_exec(init))
warn("script needs dp output table data\n");
break;
- case 5:
+ case 5: /* CONDITION_ID_ASSR_SUPPORT. */
if (!(init_rdauxr(init, 0x0d) & 1))
init_exec_set(init, false);
break;
+ case 7: /* CONDITION_ID_NO_PANEL_SEQ_DELAYS. */
+ init_exec_set(init, false);
+ break;
default:
warn("INIT_GENERIC_CONDITON: unknown 0x%02x\n", cond);
init->offset += size;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
index 3ef505a5c01b..f3c388932b6f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
@@ -13,4 +13,4 @@ nvkm-y += nvkm/subdev/devinit/gf100.o
nvkm-y += nvkm/subdev/devinit/gm107.o
nvkm-y += nvkm/subdev/devinit/gm200.o
nvkm-y += nvkm/subdev/devinit/gv100.o
-nvkm-y += nvkm/subdev/devinit/tu104.o
+nvkm-y += nvkm/subdev/devinit/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c
index aae87b3fc429..397670e72fff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c
@@ -26,7 +26,7 @@
#include <subdev/clk/pll.h>
static int
-tu104_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
+tu102_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
{
struct nvkm_subdev *subdev = &init->subdev;
struct nvkm_device *device = subdev->device;
@@ -66,7 +66,7 @@ tu104_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
}
static int
-tu104_devinit_post(struct nvkm_devinit *base, bool post)
+tu102_devinit_post(struct nvkm_devinit *base, bool post)
{
struct nv50_devinit *init = nv50_devinit(base);
gm200_devinit_preos(init, post);
@@ -74,16 +74,16 @@ tu104_devinit_post(struct nvkm_devinit *base, bool post)
}
static const struct nvkm_devinit_func
-tu104_devinit = {
+tu102_devinit = {
.init = nv50_devinit_init,
- .post = tu104_devinit_post,
- .pll_set = tu104_devinit_pll_set,
+ .post = tu102_devinit_post,
+ .pll_set = tu102_devinit_pll_set,
.disable = gm107_devinit_disable,
};
int
-tu104_devinit_new(struct nvkm_device *device, int index,
+tu102_devinit_new(struct nvkm_device *device, int index,
struct nvkm_devinit **pinit)
{
- return nv50_devinit_new_(&tu104_devinit, device, index, pinit);
+ return nv50_devinit_new_(&tu102_devinit, device, index, pinit);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild
index 794eb1745b2f..42586267fc08 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild
@@ -1,4 +1,5 @@
nvkm-y += nvkm/subdev/fault/base.o
+nvkm-y += nvkm/subdev/fault/user.o
nvkm-y += nvkm/subdev/fault/gp100.o
nvkm-y += nvkm/subdev/fault/gv100.o
-nvkm-y += nvkm/subdev/fault/tu104.o
+nvkm-y += nvkm/subdev/fault/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
index 4ba1e21e8fda..ca251560d3e0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
@@ -176,5 +176,7 @@ nvkm_fault_new_(const struct nvkm_fault_func *func, struct nvkm_device *device,
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_fault, device, index, &fault->subdev);
fault->func = func;
+ fault->user.ctor = nvkm_ufault_new;
+ fault->user.base = func->user.base;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
index 8fb96fe614f9..4f3c4e091117 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
@@ -23,6 +23,8 @@
#include <subdev/mc.h>
+#include <nvif/class.h>
+
static void
gp100_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
{
@@ -69,6 +71,7 @@ gp100_fault = {
.buffer.init = gp100_fault_buffer_init,
.buffer.fini = gp100_fault_buffer_fini,
.buffer.intr = gp100_fault_buffer_intr,
+ .user = { { 0, 0, MAXWELL_FAULT_BUFFER_A }, 0 },
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
index 6fc54e17c935..6747f09c2dc3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
@@ -25,6 +25,8 @@
#include <subdev/mmu.h>
#include <engine/fifo.h>
+#include <nvif/class.h>
+
static void
gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer)
{
@@ -166,6 +168,13 @@ gv100_fault_intr(struct nvkm_fault *fault)
}
}
+ if (stat & 0x08000000) {
+ if (fault->buffer[1]) {
+ nvkm_event_send(&fault->event, 1, 1, NULL, 0);
+ stat &= ~0x08000000;
+ }
+ }
+
if (stat) {
nvkm_debug(subdev, "intr %08x\n", stat);
}
@@ -208,6 +217,13 @@ gv100_fault = {
.buffer.init = gv100_fault_buffer_init,
.buffer.fini = gv100_fault_buffer_fini,
.buffer.intr = gv100_fault_buffer_intr,
+ /*TODO: Figure out how to expose non-replayable fault buffer, which,
+ * for some reason, is where recoverable CE faults appear...
+ *
+ * It's a bit tricky, as both NVKM and SVM will need access to
+ * the non-replayable fault buffer.
+ */
+ .user = { { 0, 0, VOLTA_FAULT_BUFFER_A }, 1 },
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
index 8ca8b2876dad..975e66ac6344 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
@@ -34,7 +34,14 @@ struct nvkm_fault_func {
void (*fini)(struct nvkm_fault_buffer *);
void (*intr)(struct nvkm_fault_buffer *, bool enable);
} buffer;
+ struct {
+ struct nvkm_sclass base;
+ int rp;
+ } user;
};
int gv100_fault_oneinit(struct nvkm_fault *);
+
+int nvkm_ufault_new(struct nvkm_device *, const struct nvkm_oclass *,
+ void *, u32, struct nvkm_object **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
index 9c8a3adf99d7..fa1dfe5692b0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
@@ -28,7 +28,7 @@
#include <nvif/class.h>
static void
-tu104_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
+tu102_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
{
/*XXX: Earlier versions of RM touched the old regs on Turing,
* which don't appear to actually work anymore, but newer
@@ -37,7 +37,7 @@ tu104_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
}
static void
-tu104_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
+tu102_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
{
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
@@ -45,7 +45,7 @@ tu104_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
}
static void
-tu104_fault_buffer_init(struct nvkm_fault_buffer *buffer)
+tu102_fault_buffer_init(struct nvkm_fault_buffer *buffer)
{
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
@@ -57,7 +57,7 @@ tu104_fault_buffer_init(struct nvkm_fault_buffer *buffer)
}
static void
-tu104_fault_buffer_info(struct nvkm_fault_buffer *buffer)
+tu102_fault_buffer_info(struct nvkm_fault_buffer *buffer)
{
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
@@ -70,7 +70,7 @@ tu104_fault_buffer_info(struct nvkm_fault_buffer *buffer)
}
static void
-tu104_fault_intr_fault(struct nvkm_fault *fault)
+tu102_fault_intr_fault(struct nvkm_fault *fault)
{
struct nvkm_subdev *subdev = &fault->subdev;
struct nvkm_device *device = subdev->device;
@@ -96,14 +96,14 @@ tu104_fault_intr_fault(struct nvkm_fault *fault)
}
static void
-tu104_fault_intr(struct nvkm_fault *fault)
+tu102_fault_intr(struct nvkm_fault *fault)
{
struct nvkm_subdev *subdev = &fault->subdev;
struct nvkm_device *device = subdev->device;
u32 stat = nvkm_rd32(device, 0xb83094);
if (stat & 0x80000000) {
- tu104_fault_intr_fault(fault);
+ tu102_fault_intr_fault(fault);
nvkm_wr32(device, 0xb83094, 0x80000000);
stat &= ~0x80000000;
}
@@ -129,7 +129,7 @@ tu104_fault_intr(struct nvkm_fault *fault)
}
static void
-tu104_fault_fini(struct nvkm_fault *fault)
+tu102_fault_fini(struct nvkm_fault *fault)
{
nvkm_notify_put(&fault->nrpfb);
if (fault->buffer[0])
@@ -138,7 +138,7 @@ tu104_fault_fini(struct nvkm_fault *fault)
}
static void
-tu104_fault_init(struct nvkm_fault *fault)
+tu102_fault_init(struct nvkm_fault *fault)
{
/*XXX: enable priv faults */
fault->func->buffer.init(fault->buffer[0]);
@@ -146,22 +146,23 @@ tu104_fault_init(struct nvkm_fault *fault)
}
static const struct nvkm_fault_func
-tu104_fault = {
+tu102_fault = {
.oneinit = gv100_fault_oneinit,
- .init = tu104_fault_init,
- .fini = tu104_fault_fini,
- .intr = tu104_fault_intr,
+ .init = tu102_fault_init,
+ .fini = tu102_fault_fini,
+ .intr = tu102_fault_intr,
.buffer.nr = 2,
.buffer.entry_size = 32,
- .buffer.info = tu104_fault_buffer_info,
- .buffer.init = tu104_fault_buffer_init,
- .buffer.fini = tu104_fault_buffer_fini,
- .buffer.intr = tu104_fault_buffer_intr,
+ .buffer.info = tu102_fault_buffer_info,
+ .buffer.init = tu102_fault_buffer_init,
+ .buffer.fini = tu102_fault_buffer_fini,
+ .buffer.intr = tu102_fault_buffer_intr,
+ .user = { { 0, 0, VOLTA_FAULT_BUFFER_A }, 1 },
};
int
-tu104_fault_new(struct nvkm_device *device, int index,
+tu102_fault_new(struct nvkm_device *device, int index,
struct nvkm_fault **pfault)
{
- return nvkm_fault_new_(&tu104_fault, device, index, pfault);
+ return nvkm_fault_new_(&tu102_fault, device, index, pfault);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c
new file mode 100644
index 000000000000..ac835c9582fd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+#include <core/memory.h>
+#include <subdev/mmu.h>
+
+#include <nvif/clb069.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_ufault_map(struct nvkm_object *object, void *argv, u32 argc,
+ enum nvkm_object_map *type, u64 *addr, u64 *size)
+{
+ struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
+ struct nvkm_device *device = buffer->fault->subdev.device;
+ *type = NVKM_OBJECT_MAP_IO;
+ *addr = device->func->resource_addr(device, 3) + buffer->addr;
+ *size = nvkm_memory_size(buffer->mem);
+ return 0;
+}
+
+static int
+nvkm_ufault_ntfy(struct nvkm_object *object, u32 type,
+ struct nvkm_event **pevent)
+{
+ struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
+ if (type == NVB069_V0_NTFY_FAULT) {
+ *pevent = &buffer->fault->event;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int
+nvkm_ufault_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
+ buffer->fault->func->buffer.fini(buffer);
+ return 0;
+}
+
+static int
+nvkm_ufault_init(struct nvkm_object *object)
+{
+ struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object);
+ buffer->fault->func->buffer.init(buffer);
+ return 0;
+}
+
+static void *
+nvkm_ufault_dtor(struct nvkm_object *object)
+{
+ return NULL;
+}
+
+static const struct nvkm_object_func
+nvkm_ufault = {
+ .dtor = nvkm_ufault_dtor,
+ .init = nvkm_ufault_init,
+ .fini = nvkm_ufault_fini,
+ .ntfy = nvkm_ufault_ntfy,
+ .map = nvkm_ufault_map,
+};
+
+int
+nvkm_ufault_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
+ void *argv, u32 argc, struct nvkm_object **pobject)
+{
+ union {
+ struct nvif_clb069_v0 v0;
+ } *args = argv;
+ struct nvkm_fault *fault = device->fault;
+ struct nvkm_fault_buffer *buffer = fault->buffer[fault->func->user.rp];
+ int ret = -ENOSYS;
+
+ if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
+ args->v0.entries = buffer->entries;
+ args->v0.get = buffer->get;
+ args->v0.put = buffer->put;
+ } else
+ return ret;
+
+ nvkm_object_ctor(&nvkm_ufault, oclass, &buffer->object);
+ *pobject = &buffer->object;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
index 60ece0a8a2e1..1d2d6bae73cd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
@@ -87,7 +87,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram)
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
/* XXX: Get these values from the VBIOS instead */
DLL = !(ram->mr[1] & 0x1);
- RON = !(ram->mr[1] & 0x300) >> 8;
+ RON = !((ram->mr[1] & 0x300) >> 8);
break;
default:
return -ENOSYS;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
new file mode 100644
index 000000000000..26fc6feb807e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/subdev/gsp/gv100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c
new file mode 100644
index 000000000000..dccfaf1162e2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <subdev/gsp.h>
+#include <subdev/top.h>
+#include <engine/falcon.h>
+
+static int
+gv100_gsp_oneinit(struct nvkm_subdev *subdev)
+{
+ struct nvkm_gsp *gsp = nvkm_gsp(subdev);
+
+ gsp->addr = nvkm_top_addr(subdev->device, subdev->index);
+ if (!gsp->addr)
+ return -EINVAL;
+
+ return nvkm_falcon_v1_new(subdev, "GSP", gsp->addr, &gsp->falcon);
+}
+
+static void *
+gv100_gsp_dtor(struct nvkm_subdev *subdev)
+{
+ struct nvkm_gsp *gsp = nvkm_gsp(subdev);
+ nvkm_falcon_del(&gsp->falcon);
+ return gsp;
+}
+
+static const struct nvkm_subdev_func
+gv100_gsp = {
+ .dtor = gv100_gsp_dtor,
+ .oneinit = gv100_gsp_oneinit,
+};
+
+int
+gv100_gsp_new(struct nvkm_device *device, int index, struct nvkm_gsp **pgsp)
+{
+ struct nvkm_gsp *gsp;
+
+ if (!(gsp = *pgsp = kzalloc(sizeof(*gsp), GFP_KERNEL)))
+ return -ENOMEM;
+
+ nvkm_subdev_ctor(&gv100_gsp, device, index, &gsp->subdev);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
index f3b06329c338..c64e399326b3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
@@ -12,4 +12,4 @@ nvkm-y += nvkm/subdev/mc/gk104.o
nvkm-y += nvkm/subdev/mc/gk20a.o
nvkm-y += nvkm/subdev/mc/gp100.o
nvkm-y += nvkm/subdev/mc/gp10b.o
-nvkm-y += nvkm/subdev/mc/tu104.o
+nvkm-y += nvkm/subdev/mc/tu102.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c
index b7165bd18999..d098c44a4fcb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c
@@ -22,7 +22,7 @@
#include "priv.h"
static void
-tu104_mc_intr_hack(struct nvkm_mc *mc, bool *handled)
+tu102_mc_intr_hack(struct nvkm_mc *mc, bool *handled)
{
struct nvkm_device *device = mc->subdev.device;
u32 stat = nvkm_rd32(device, 0xb81010);
@@ -37,19 +37,19 @@ tu104_mc_intr_hack(struct nvkm_mc *mc, bool *handled)
}
static const struct nvkm_mc_func
-tu104_mc = {
+tu102_mc = {
.init = nv50_mc_init,
.intr = gp100_mc_intr,
.intr_unarm = gp100_mc_intr_unarm,
.intr_rearm = gp100_mc_intr_rearm,
.intr_mask = gp100_mc_intr_mask,
.intr_stat = gf100_mc_intr_stat,
- .intr_hack = tu104_mc_intr_hack,
+ .intr_hack = tu102_mc_intr_hack,
.reset = gk104_mc_reset,
};
int
-tu104_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
+tu102_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
{
- return gp100_mc_new_(&tu104_mc, device, index, pmc);
+ return gp100_mc_new_(&tu102_mc, device, index, pmc);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
index 8966180b36cc..db9c56028f21 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
@@ -13,7 +13,7 @@ nvkm-y += nvkm/subdev/mmu/gm20b.o
nvkm-y += nvkm/subdev/mmu/gp100.o
nvkm-y += nvkm/subdev/mmu/gp10b.o
nvkm-y += nvkm/subdev/mmu/gv100.o
-nvkm-y += nvkm/subdev/mmu/tu104.o
+nvkm-y += nvkm/subdev/mmu/tu102.o
nvkm-y += nvkm/subdev/mmu/mem.o
nvkm-y += nvkm/subdev/mmu/memnv04.o
@@ -34,7 +34,7 @@ nvkm-y += nvkm/subdev/mmu/vmmgm20b.o
nvkm-y += nvkm/subdev/mmu/vmmgp100.o
nvkm-y += nvkm/subdev/mmu/vmmgp10b.o
nvkm-y += nvkm/subdev/mmu/vmmgv100.o
-nvkm-y += nvkm/subdev/mmu/vmmtu104.o
+nvkm-y += nvkm/subdev/mmu/vmmtu102.o
nvkm-y += nvkm/subdev/mmu/umem.o
nvkm-y += nvkm/subdev/mmu/ummu.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp100.c
index 651b8805c67c..65cb9d28e60e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp100.c
@@ -31,7 +31,7 @@ gp100_mmu = {
.dma_bits = 47,
.mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
.mem = {{ -1, 0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
- .vmm = {{ -1, -1, NVIF_CLASS_VMM_GP100}, gp100_vmm_new },
+ .vmm = {{ -1, 0, NVIF_CLASS_VMM_GP100}, gp100_vmm_new },
.kind = gm200_mmu_kind,
.kind_sys = true,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b.c
index 3bd3db31e0bb..0a50be9a785a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b.c
@@ -31,7 +31,7 @@ gp10b_mmu = {
.dma_bits = 47,
.mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
.mem = {{ -1, -1, NVIF_CLASS_MEM_GF100}, .umap = gf100_mem_map },
- .vmm = {{ -1, -1, NVIF_CLASS_VMM_GP100}, gp10b_vmm_new },
+ .vmm = {{ -1, 0, NVIF_CLASS_VMM_GP100}, gp10b_vmm_new },
.kind = gm200_mmu_kind,
.kind_sys = true,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gv100.c
index f666cb57f69e..e0997eedd6d9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gv100.c
@@ -31,7 +31,7 @@ gv100_mmu = {
.dma_bits = 47,
.mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
.mem = {{ -1, 0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
- .vmm = {{ -1, -1, NVIF_CLASS_VMM_GP100}, gv100_vmm_new },
+ .vmm = {{ -1, 0, NVIF_CLASS_VMM_GP100}, gv100_vmm_new },
.kind = gm200_mmu_kind,
.kind_sys = true,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
index 948a48c21be4..2ad1102a4e31 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
@@ -28,7 +28,7 @@ struct nvkm_mmu_func {
struct {
struct nvkm_sclass user;
- int (*ctor)(struct nvkm_mmu *, u64 addr, u64 size,
+ int (*ctor)(struct nvkm_mmu *, bool managed, u64 addr, u64 size,
void *argv, u32 argc, struct lock_class_key *,
const char *name, struct nvkm_vmm **);
bool global;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
index 8e6f4096170d..c0db0ce10cba 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
@@ -27,17 +27,17 @@
#include <nvif/class.h>
static const struct nvkm_mmu_func
-tu104_mmu = {
+tu102_mmu = {
.dma_bits = 47,
.mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
.mem = {{ -1, 0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
- .vmm = {{ -1, 0, NVIF_CLASS_VMM_GP100}, tu104_vmm_new },
+ .vmm = {{ -1, 0, NVIF_CLASS_VMM_GP100}, tu102_vmm_new },
.kind = gm200_mmu_kind,
.kind_sys = true,
};
int
-tu104_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
+tu102_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
{
- return nvkm_mmu_new_(&tu104_mmu, device, index, pmmu);
+ return nvkm_mmu_new_(&tu102_mmu, device, index, pmmu);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
index 6889076097ec..c43b8248c682 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
@@ -43,6 +43,69 @@ nvkm_uvmm_search(struct nvkm_client *client, u64 handle)
}
static int
+nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
+{
+ struct nvkm_client *client = uvmm->object.client;
+ union {
+ struct nvif_vmm_pfnclr_v0 v0;
+ } *args = argv;
+ struct nvkm_vmm *vmm = uvmm->vmm;
+ int ret = -ENOSYS;
+ u64 addr, size;
+
+ if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
+ addr = args->v0.addr;
+ size = args->v0.size;
+ } else
+ return ret;
+
+ if (!client->super)
+ return -ENOENT;
+
+ if (size) {
+ mutex_lock(&vmm->mutex);
+ ret = nvkm_vmm_pfn_unmap(vmm, addr, size);
+ mutex_unlock(&vmm->mutex);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_uvmm_mthd_pfnmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
+{
+ struct nvkm_client *client = uvmm->object.client;
+ union {
+ struct nvif_vmm_pfnmap_v0 v0;
+ } *args = argv;
+ struct nvkm_vmm *vmm = uvmm->vmm;
+ int ret = -ENOSYS;
+ u64 addr, size, *phys;
+ u8 page;
+
+ if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, true))) {
+ page = args->v0.page;
+ addr = args->v0.addr;
+ size = args->v0.size;
+ phys = args->v0.phys;
+ if (argc != (size >> page) * sizeof(args->v0.phys[0]))
+ return -EINVAL;
+ } else
+ return ret;
+
+ if (!client->super)
+ return -ENOENT;
+
+ if (size) {
+ mutex_lock(&vmm->mutex);
+ ret = nvkm_vmm_pfn_map(vmm, page, addr, size, phys);
+ mutex_unlock(&vmm->mutex);
+ }
+
+ return ret;
+}
+
+static int
nvkm_uvmm_mthd_unmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
{
struct nvkm_client *client = uvmm->object.client;
@@ -78,7 +141,7 @@ nvkm_uvmm_mthd_unmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
goto done;
}
- nvkm_vmm_unmap_locked(vmm, vma);
+ nvkm_vmm_unmap_locked(vmm, vma, false);
ret = 0;
done:
mutex_unlock(&vmm->mutex);
@@ -124,6 +187,11 @@ nvkm_uvmm_mthd_map(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
goto fail;
}
+ if (ret = -EINVAL, vma->mapped && !vma->memory) {
+ VMM_DEBUG(vmm, "pfnmap %016llx", addr);
+ goto fail;
+ }
+
if (ret = -EINVAL, vma->addr != addr || vma->size != size) {
if (addr + size > vma->addr + vma->size || vma->memory ||
(vma->refd == NVKM_VMA_PAGE_NONE && !vma->mapref)) {
@@ -271,6 +339,15 @@ nvkm_uvmm_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
case NVIF_VMM_V0_PUT : return nvkm_uvmm_mthd_put (uvmm, argv, argc);
case NVIF_VMM_V0_MAP : return nvkm_uvmm_mthd_map (uvmm, argv, argc);
case NVIF_VMM_V0_UNMAP : return nvkm_uvmm_mthd_unmap (uvmm, argv, argc);
+ case NVIF_VMM_V0_PFNMAP: return nvkm_uvmm_mthd_pfnmap(uvmm, argv, argc);
+ case NVIF_VMM_V0_PFNCLR: return nvkm_uvmm_mthd_pfnclr(uvmm, argv, argc);
+ case NVIF_VMM_V0_MTHD(0x00) ... NVIF_VMM_V0_MTHD(0x7f):
+ if (uvmm->vmm->func->mthd) {
+ return uvmm->vmm->func->mthd(uvmm->vmm,
+ uvmm->object.client,
+ mthd, argv, argc);
+ }
+ break;
default:
break;
}
@@ -304,8 +381,10 @@ nvkm_uvmm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_uvmm *uvmm;
int ret = -ENOSYS;
u64 addr, size;
+ bool managed;
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, more))) {
+ managed = args->v0.managed != 0;
addr = args->v0.addr;
size = args->v0.size;
} else
@@ -317,7 +396,7 @@ nvkm_uvmm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
*pobject = &uvmm->object;
if (!mmu->vmm) {
- ret = mmu->func->vmm.ctor(mmu, addr, size, argv, argc,
+ ret = mmu->func->vmm.ctor(mmu, managed, addr, size, argv, argc,
NULL, "user", &uvmm->vmm);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
index 6b87fff014b3..fa93f964e6a4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
@@ -255,11 +255,23 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
}
static bool
-nvkm_vmm_unref_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
+nvkm_vmm_unref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
{
const struct nvkm_vmm_desc *desc = it->desc;
const int type = desc->type == SPT;
struct nvkm_vmm_pt *pgt = it->pt[0];
+ bool dma;
+
+ if (pfn) {
+ /* Need to clear PTE valid bits before we dma_unmap_page(). */
+ dma = desc->func->pfn_clear(it->vmm, pgt->pt[type], ptei, ptes);
+ if (dma) {
+ /* GPU may have cached the PT, flush before unmap. */
+ nvkm_vmm_flush_mark(it);
+ nvkm_vmm_flush(it);
+ desc->func->pfn_unmap(it->vmm, pgt->pt[type], ptei, ptes);
+ }
+ }
/* Drop PTE references. */
pgt->refs[type] -= ptes;
@@ -349,7 +361,7 @@ nvkm_vmm_ref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
}
static bool
-nvkm_vmm_ref_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
+nvkm_vmm_ref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
{
const struct nvkm_vmm_desc *desc = it->desc;
const int type = desc->type == SPT;
@@ -379,7 +391,7 @@ nvkm_vmm_sparse_ptes(const struct nvkm_vmm_desc *desc,
}
static bool
-nvkm_vmm_sparse_unref_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
+nvkm_vmm_sparse_unref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
{
struct nvkm_vmm_pt *pt = it->pt[0];
if (it->desc->type == PGD)
@@ -387,14 +399,14 @@ nvkm_vmm_sparse_unref_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
else
if (it->desc->type == LPT)
memset(&pt->pte[ptei], 0x00, sizeof(pt->pte[0]) * ptes);
- return nvkm_vmm_unref_ptes(it, ptei, ptes);
+ return nvkm_vmm_unref_ptes(it, pfn, ptei, ptes);
}
static bool
-nvkm_vmm_sparse_ref_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
+nvkm_vmm_sparse_ref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
{
nvkm_vmm_sparse_ptes(it->desc, it->pt[0], ptei, ptes);
- return nvkm_vmm_ref_ptes(it, ptei, ptes);
+ return nvkm_vmm_ref_ptes(it, pfn, ptei, ptes);
}
static bool
@@ -487,8 +499,8 @@ nvkm_vmm_ref_swpt(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgd, u32 pdei)
static inline u64
nvkm_vmm_iter(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
- u64 addr, u64 size, const char *name, bool ref,
- bool (*REF_PTES)(struct nvkm_vmm_iter *, u32, u32),
+ u64 addr, u64 size, const char *name, bool ref, bool pfn,
+ bool (*REF_PTES)(struct nvkm_vmm_iter *, bool pfn, u32, u32),
nvkm_vmm_pte_func MAP_PTES, struct nvkm_vmm_map *map,
nvkm_vmm_pxe_func CLR_PTES)
{
@@ -548,7 +560,7 @@ nvkm_vmm_iter(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
}
/* Handle PTE updates. */
- if (!REF_PTES || REF_PTES(&it, ptei, ptes)) {
+ if (!REF_PTES || REF_PTES(&it, pfn, ptei, ptes)) {
struct nvkm_mmu_pt *pt = pgt->pt[type];
if (MAP_PTES || CLR_PTES) {
if (MAP_PTES)
@@ -590,7 +602,7 @@ static void
nvkm_vmm_ptes_sparse_put(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
u64 addr, u64 size)
{
- nvkm_vmm_iter(vmm, page, addr, size, "sparse unref", false,
+ nvkm_vmm_iter(vmm, page, addr, size, "sparse unref", false, false,
nvkm_vmm_sparse_unref_ptes, NULL, NULL,
page->desc->func->invalid ?
page->desc->func->invalid : page->desc->func->unmap);
@@ -602,8 +614,8 @@ nvkm_vmm_ptes_sparse_get(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
{
if ((page->type & NVKM_VMM_PAGE_SPARSE)) {
u64 fail = nvkm_vmm_iter(vmm, page, addr, size, "sparse ref",
- true, nvkm_vmm_sparse_ref_ptes, NULL,
- NULL, page->desc->func->sparse);
+ true, false, nvkm_vmm_sparse_ref_ptes,
+ NULL, NULL, page->desc->func->sparse);
if (fail != ~0ULL) {
if ((size = fail - addr))
nvkm_vmm_ptes_sparse_put(vmm, page, addr, size);
@@ -666,11 +678,11 @@ nvkm_vmm_ptes_sparse(struct nvkm_vmm *vmm, u64 addr, u64 size, bool ref)
static void
nvkm_vmm_ptes_unmap_put(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
- u64 addr, u64 size, bool sparse)
+ u64 addr, u64 size, bool sparse, bool pfn)
{
const struct nvkm_vmm_desc_func *func = page->desc->func;
nvkm_vmm_iter(vmm, page, addr, size, "unmap + unref",
- false, nvkm_vmm_unref_ptes, NULL, NULL,
+ false, pfn, nvkm_vmm_unref_ptes, NULL, NULL,
sparse ? func->sparse : func->invalid ? func->invalid :
func->unmap);
}
@@ -681,10 +693,10 @@ nvkm_vmm_ptes_get_map(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
nvkm_vmm_pte_func func)
{
u64 fail = nvkm_vmm_iter(vmm, page, addr, size, "ref + map", true,
- nvkm_vmm_ref_ptes, func, map, NULL);
+ false, nvkm_vmm_ref_ptes, func, map, NULL);
if (fail != ~0ULL) {
if ((size = fail - addr))
- nvkm_vmm_ptes_unmap_put(vmm, page, addr, size, false);
+ nvkm_vmm_ptes_unmap_put(vmm, page, addr, size, false, false);
return -ENOMEM;
}
return 0;
@@ -692,10 +704,11 @@ nvkm_vmm_ptes_get_map(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
static void
nvkm_vmm_ptes_unmap(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
- u64 addr, u64 size, bool sparse)
+ u64 addr, u64 size, bool sparse, bool pfn)
{
const struct nvkm_vmm_desc_func *func = page->desc->func;
- nvkm_vmm_iter(vmm, page, addr, size, "unmap", false, NULL, NULL, NULL,
+ nvkm_vmm_iter(vmm, page, addr, size, "unmap", false, pfn,
+ NULL, NULL, NULL,
sparse ? func->sparse : func->invalid ? func->invalid :
func->unmap);
}
@@ -705,7 +718,7 @@ nvkm_vmm_ptes_map(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
u64 addr, u64 size, struct nvkm_vmm_map *map,
nvkm_vmm_pte_func func)
{
- nvkm_vmm_iter(vmm, page, addr, size, "map", false,
+ nvkm_vmm_iter(vmm, page, addr, size, "map", false, false,
NULL, func, map, NULL);
}
@@ -713,7 +726,7 @@ static void
nvkm_vmm_ptes_put(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
u64 addr, u64 size)
{
- nvkm_vmm_iter(vmm, page, addr, size, "unref", false,
+ nvkm_vmm_iter(vmm, page, addr, size, "unref", false, false,
nvkm_vmm_unref_ptes, NULL, NULL, NULL);
}
@@ -721,7 +734,7 @@ static int
nvkm_vmm_ptes_get(struct nvkm_vmm *vmm, const struct nvkm_vmm_page *page,
u64 addr, u64 size)
{
- u64 fail = nvkm_vmm_iter(vmm, page, addr, size, "ref", true,
+ u64 fail = nvkm_vmm_iter(vmm, page, addr, size, "ref", true, false,
nvkm_vmm_ref_ptes, NULL, NULL, NULL);
if (fail != ~0ULL) {
if (fail != addr)
@@ -763,6 +776,7 @@ nvkm_vma_tail(struct nvkm_vma *vma, u64 tail)
new->part = vma->part;
new->user = vma->user;
new->busy = vma->busy;
+ new->mapped = vma->mapped;
list_add(&new->head, &vma->head);
return new;
}
@@ -935,11 +949,40 @@ nvkm_vmm_node_split(struct nvkm_vmm *vmm,
}
static void
+nvkm_vma_dump(struct nvkm_vma *vma)
+{
+ printk(KERN_ERR "%016llx %016llx %c%c%c%c%c%c%c%c%c %p\n",
+ vma->addr, (u64)vma->size,
+ vma->used ? '-' : 'F',
+ vma->mapref ? 'R' : '-',
+ vma->sparse ? 'S' : '-',
+ vma->page != NVKM_VMA_PAGE_NONE ? '0' + vma->page : '-',
+ vma->refd != NVKM_VMA_PAGE_NONE ? '0' + vma->refd : '-',
+ vma->part ? 'P' : '-',
+ vma->user ? 'U' : '-',
+ vma->busy ? 'B' : '-',
+ vma->mapped ? 'M' : '-',
+ vma->memory);
+}
+
+static void
+nvkm_vmm_dump(struct nvkm_vmm *vmm)
+{
+ struct nvkm_vma *vma;
+ list_for_each_entry(vma, &vmm->list, head) {
+ nvkm_vma_dump(vma);
+ }
+}
+
+static void
nvkm_vmm_dtor(struct nvkm_vmm *vmm)
{
struct nvkm_vma *vma;
struct rb_node *node;
+ if (0)
+ nvkm_vmm_dump(vmm);
+
while ((node = rb_first(&vmm->root))) {
struct nvkm_vma *vma = rb_entry(node, typeof(*vma), tree);
nvkm_vmm_put(vmm, &vma);
@@ -972,16 +1015,32 @@ nvkm_vmm_dtor(struct nvkm_vmm *vmm)
}
}
+static int
+nvkm_vmm_ctor_managed(struct nvkm_vmm *vmm, u64 addr, u64 size)
+{
+ struct nvkm_vma *vma;
+ if (!(vma = nvkm_vma_new(addr, size)))
+ return -ENOMEM;
+ vma->mapref = true;
+ vma->sparse = false;
+ vma->used = true;
+ vma->user = true;
+ nvkm_vmm_node_insert(vmm, vma);
+ list_add_tail(&vma->head, &vmm->list);
+ return 0;
+}
+
int
nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
- u32 pd_header, u64 addr, u64 size, struct lock_class_key *key,
- const char *name, struct nvkm_vmm *vmm)
+ u32 pd_header, bool managed, u64 addr, u64 size,
+ struct lock_class_key *key, const char *name,
+ struct nvkm_vmm *vmm)
{
static struct lock_class_key _key;
const struct nvkm_vmm_page *page = func->page;
const struct nvkm_vmm_desc *desc;
struct nvkm_vma *vma;
- int levels, bits = 0;
+ int levels, bits = 0, ret;
vmm->func = func;
vmm->mmu = mmu;
@@ -1009,11 +1068,6 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
if (WARN_ON(levels > NVKM_VMM_LEVELS_MAX))
return -EINVAL;
- vmm->start = addr;
- vmm->limit = size ? (addr + size) : (1ULL << bits);
- if (vmm->start > vmm->limit || vmm->limit > (1ULL << bits))
- return -EINVAL;
-
/* Allocate top-level page table. */
vmm->pd = nvkm_vmm_pt_new(desc, false, NULL);
if (!vmm->pd)
@@ -1036,50 +1090,273 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
vmm->free = RB_ROOT;
vmm->root = RB_ROOT;
- if (!(vma = nvkm_vma_new(vmm->start, vmm->limit - vmm->start)))
- return -ENOMEM;
+ if (managed) {
+ /* Address-space will be managed by the client for the most
+ * part, except for a specified area where NVKM allocations
+ * are allowed to be placed.
+ */
+ vmm->start = 0;
+ vmm->limit = 1ULL << bits;
+ if (addr + size < addr || addr + size > vmm->limit)
+ return -EINVAL;
+
+ /* Client-managed area before the NVKM-managed area. */
+ if (addr && (ret = nvkm_vmm_ctor_managed(vmm, 0, addr)))
+ return ret;
+
+ /* NVKM-managed area. */
+ if (size) {
+ if (!(vma = nvkm_vma_new(addr, size)))
+ return -ENOMEM;
+ nvkm_vmm_free_insert(vmm, vma);
+ list_add_tail(&vma->head, &vmm->list);
+ }
+
+ /* Client-managed area after the NVKM-managed area. */
+ addr = addr + size;
+ size = vmm->limit - addr;
+ if (size && (ret = nvkm_vmm_ctor_managed(vmm, addr, size)))
+ return ret;
+ } else {
+ /* Address-space fully managed by NVKM, requiring calls to
+ * nvkm_vmm_get()/nvkm_vmm_put() to allocate address-space.
+ */
+ vmm->start = addr;
+ vmm->limit = size ? (addr + size) : (1ULL << bits);
+ if (vmm->start > vmm->limit || vmm->limit > (1ULL << bits))
+ return -EINVAL;
+
+ if (!(vma = nvkm_vma_new(vmm->start, vmm->limit - vmm->start)))
+ return -ENOMEM;
+
+ nvkm_vmm_free_insert(vmm, vma);
+ list_add(&vma->head, &vmm->list);
+ }
- nvkm_vmm_free_insert(vmm, vma);
- list_add(&vma->head, &vmm->list);
return 0;
}
int
nvkm_vmm_new_(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
- u32 hdr, u64 addr, u64 size, struct lock_class_key *key,
- const char *name, struct nvkm_vmm **pvmm)
+ u32 hdr, bool managed, u64 addr, u64 size,
+ struct lock_class_key *key, const char *name,
+ struct nvkm_vmm **pvmm)
{
if (!(*pvmm = kzalloc(sizeof(**pvmm), GFP_KERNEL)))
return -ENOMEM;
- return nvkm_vmm_ctor(func, mmu, hdr, addr, size, key, name, *pvmm);
+ return nvkm_vmm_ctor(func, mmu, hdr, managed, addr, size, key, name, *pvmm);
+}
+
+static struct nvkm_vma *
+nvkm_vmm_pfn_split_merge(struct nvkm_vmm *vmm, struct nvkm_vma *vma,
+ u64 addr, u64 size, u8 page, bool map)
+{
+ struct nvkm_vma *prev = NULL;
+ struct nvkm_vma *next = NULL;
+
+ if (vma->addr == addr && vma->part && (prev = node(vma, prev))) {
+ if (prev->memory || prev->mapped != map)
+ prev = NULL;
+ }
+
+ if (vma->addr + vma->size == addr + size && (next = node(vma, next))) {
+ if (!next->part ||
+ next->memory || next->mapped != map)
+ next = NULL;
+ }
+
+ if (prev || next)
+ return nvkm_vmm_node_merge(vmm, prev, vma, next, size);
+ return nvkm_vmm_node_split(vmm, vma, addr, size);
+}
+
+int
+nvkm_vmm_pfn_unmap(struct nvkm_vmm *vmm, u64 addr, u64 size)
+{
+ struct nvkm_vma *vma = nvkm_vmm_node_search(vmm, addr);
+ struct nvkm_vma *next;
+ u64 limit = addr + size;
+ u64 start = addr;
+
+ if (!vma)
+ return -EINVAL;
+
+ do {
+ if (!vma->mapped || vma->memory)
+ continue;
+
+ size = min(limit - start, vma->size - (start - vma->addr));
+
+ nvkm_vmm_ptes_unmap_put(vmm, &vmm->func->page[vma->refd],
+ start, size, false, true);
+
+ next = nvkm_vmm_pfn_split_merge(vmm, vma, start, size, 0, false);
+ if (!WARN_ON(!next)) {
+ vma = next;
+ vma->refd = NVKM_VMA_PAGE_NONE;
+ vma->mapped = false;
+ }
+ } while ((vma = node(vma, next)) && (start = vma->addr) < limit);
+
+ return 0;
+}
+
+/*TODO:
+ * - Avoid PT readback (for dma_unmap etc), this might end up being dealt
+ * with inside HMM, which would be a lot nicer for us to deal with.
+ * - Multiple page sizes (particularly for huge page support).
+ * - Support for systems without a 4KiB page size.
+ */
+int
+nvkm_vmm_pfn_map(struct nvkm_vmm *vmm, u8 shift, u64 addr, u64 size, u64 *pfn)
+{
+ const struct nvkm_vmm_page *page = vmm->func->page;
+ struct nvkm_vma *vma, *tmp;
+ u64 limit = addr + size;
+ u64 start = addr;
+ int pm = size >> shift;
+ int pi = 0;
+
+ /* Only support mapping where the page size of the incoming page
+ * array matches a page size available for direct mapping.
+ */
+ while (page->shift && page->shift != shift &&
+ page->desc->func->pfn == NULL)
+ page++;
+
+ if (!page->shift || !IS_ALIGNED(addr, 1ULL << shift) ||
+ !IS_ALIGNED(size, 1ULL << shift) ||
+ addr + size < addr || addr + size > vmm->limit) {
+ VMM_DEBUG(vmm, "paged map %d %d %016llx %016llx\n",
+ shift, page->shift, addr, size);
+ return -EINVAL;
+ }
+
+ if (!(vma = nvkm_vmm_node_search(vmm, addr)))
+ return -ENOENT;
+
+ do {
+ bool map = !!(pfn[pi] & NVKM_VMM_PFN_V);
+ bool mapped = vma->mapped;
+ u64 size = limit - start;
+ u64 addr = start;
+ int pn, ret = 0;
+
+ /* Narrow the operation window to cover a single action (page
+ * should be mapped or not) within a single VMA.
+ */
+ for (pn = 0; pi + pn < pm; pn++) {
+ if (map != !!(pfn[pi + pn] & NVKM_VMM_PFN_V))
+ break;
+ }
+ size = min_t(u64, size, pn << page->shift);
+ size = min_t(u64, size, vma->size + vma->addr - addr);
+
+ /* Reject any operation to unmanaged regions, and areas that
+ * have nvkm_memory objects mapped in them already.
+ */
+ if (!vma->mapref || vma->memory) {
+ ret = -EINVAL;
+ goto next;
+ }
+
+ /* In order to both properly refcount GPU page tables, and
+ * prevent "normal" mappings and these direct mappings from
+ * interfering with each other, we need to track contiguous
+ * ranges that have been mapped with this interface.
+ *
+ * Here we attempt to either split an existing VMA so we're
+ * able to flag the region as either unmapped/mapped, or to
+ * merge with adjacent VMAs that are already compatible.
+ *
+ * If the region is already compatible, nothing is required.
+ */
+ if (map != mapped) {
+ tmp = nvkm_vmm_pfn_split_merge(vmm, vma, addr, size,
+ page -
+ vmm->func->page, map);
+ if (WARN_ON(!tmp)) {
+ ret = -ENOMEM;
+ goto next;
+ }
+
+ if ((tmp->mapped = map))
+ tmp->refd = page - vmm->func->page;
+ else
+ tmp->refd = NVKM_VMA_PAGE_NONE;
+ vma = tmp;
+ }
+
+ /* Update HW page tables. */
+ if (map) {
+ struct nvkm_vmm_map args;
+ args.page = page;
+ args.pfn = &pfn[pi];
+
+ if (!mapped) {
+ ret = nvkm_vmm_ptes_get_map(vmm, page, addr,
+ size, &args, page->
+ desc->func->pfn);
+ } else {
+ nvkm_vmm_ptes_map(vmm, page, addr, size, &args,
+ page->desc->func->pfn);
+ }
+ } else {
+ if (mapped) {
+ nvkm_vmm_ptes_unmap_put(vmm, page, addr, size,
+ false, true);
+ }
+ }
+
+next:
+ /* Iterate to next operation. */
+ if (vma->addr + vma->size == addr + size)
+ vma = node(vma, next);
+ start += size;
+
+ if (ret) {
+ /* Failure is signalled by clearing the valid bit on
+ * any PFN that couldn't be modified as requested.
+ */
+ while (size) {
+ pfn[pi++] = NVKM_VMM_PFN_NONE;
+ size -= 1 << page->shift;
+ }
+ } else {
+ pi += size >> page->shift;
+ }
+ } while (vma && start < limit);
+
+ return 0;
}
void
nvkm_vmm_unmap_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
{
- struct nvkm_vma *next = node(vma, next);
struct nvkm_vma *prev = NULL;
+ struct nvkm_vma *next;
nvkm_memory_tags_put(vma->memory, vmm->mmu->subdev.device, &vma->tags);
nvkm_memory_unref(&vma->memory);
+ vma->mapped = false;
- if (!vma->part || ((prev = node(vma, prev)), prev->memory))
+ if (vma->part && (prev = node(vma, prev)) && prev->mapped)
prev = NULL;
- if (!next->part || next->memory)
+ if ((next = node(vma, next)) && (!next->part || next->mapped))
next = NULL;
nvkm_vmm_node_merge(vmm, prev, vma, next, vma->size);
}
void
-nvkm_vmm_unmap_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
+nvkm_vmm_unmap_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma, bool pfn)
{
const struct nvkm_vmm_page *page = &vmm->func->page[vma->refd];
if (vma->mapref) {
- nvkm_vmm_ptes_unmap_put(vmm, page, vma->addr, vma->size, vma->sparse);
+ nvkm_vmm_ptes_unmap_put(vmm, page, vma->addr, vma->size, vma->sparse, pfn);
vma->refd = NVKM_VMA_PAGE_NONE;
} else {
- nvkm_vmm_ptes_unmap(vmm, page, vma->addr, vma->size, vma->sparse);
+ nvkm_vmm_ptes_unmap(vmm, page, vma->addr, vma->size, vma->sparse, pfn);
}
nvkm_vmm_unmap_region(vmm, vma);
@@ -1090,7 +1367,7 @@ nvkm_vmm_unmap(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
{
if (vma->memory) {
mutex_lock(&vmm->mutex);
- nvkm_vmm_unmap_locked(vmm, vma);
+ nvkm_vmm_unmap_locked(vmm, vma, false);
mutex_unlock(&vmm->mutex);
}
}
@@ -1224,6 +1501,7 @@ nvkm_vmm_map_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma,
nvkm_memory_tags_put(vma->memory, vmm->mmu->subdev.device, &vma->tags);
nvkm_memory_unref(&vma->memory);
vma->memory = nvkm_memory_ref(map->memory);
+ vma->mapped = true;
vma->tags = map->tags;
return 0;
}
@@ -1269,14 +1547,16 @@ nvkm_vmm_put_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
if (vma->mapref || !vma->sparse) {
do {
- const bool map = next->memory != NULL;
+ const bool mem = next->memory != NULL;
+ const bool map = next->mapped;
const u8 refd = next->refd;
const u64 addr = next->addr;
u64 size = next->size;
/* Merge regions that are in the same state. */
while ((next = node(next, next)) && next->part &&
- (next->memory != NULL) == map &&
+ (next->mapped == map) &&
+ (next->memory != NULL) == mem &&
(next->refd == refd))
size += next->size;
@@ -1286,7 +1566,8 @@ nvkm_vmm_put_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
* the page tree.
*/
nvkm_vmm_ptes_unmap_put(vmm, &page[refd], addr,
- size, vma->sparse);
+ size, vma->sparse,
+ !mem);
} else
if (refd != NVKM_VMA_PAGE_NONE) {
/* Drop allocation-time PTE references. */
@@ -1301,7 +1582,7 @@ nvkm_vmm_put_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
*/
next = vma;
do {
- if (next->memory)
+ if (next->mapped)
nvkm_vmm_unmap_region(vmm, next);
} while ((next = node(vma, next)) && next->part);
@@ -1522,7 +1803,7 @@ nvkm_vmm_join(struct nvkm_vmm *vmm, struct nvkm_memory *inst)
}
static bool
-nvkm_vmm_boot_ptes(struct nvkm_vmm_iter *it, u32 ptei, u32 ptes)
+nvkm_vmm_boot_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes)
{
const struct nvkm_vmm_desc *desc = it->desc;
const int type = desc->type == SPT;
@@ -1544,7 +1825,7 @@ nvkm_vmm_boot(struct nvkm_vmm *vmm)
if (ret)
return ret;
- nvkm_vmm_iter(vmm, page, vmm->start, limit, "bootstrap", false,
+ nvkm_vmm_iter(vmm, page, vmm->start, limit, "bootstrap", false, false,
nvkm_vmm_boot_ptes, NULL, NULL, NULL);
vmm->bootstrapped = true;
return 0;
@@ -1584,7 +1865,8 @@ nvkm_vmm_new(struct nvkm_device *device, u64 addr, u64 size, void *argv,
struct nvkm_mmu *mmu = device->mmu;
struct nvkm_vmm *vmm = NULL;
int ret;
- ret = mmu->func->vmm.ctor(mmu, addr, size, argv, argc, key, name, &vmm);
+ ret = mmu->func->vmm.ctor(mmu, false, addr, size, argv, argc,
+ key, name, &vmm);
if (ret)
nvkm_vmm_unref(&vmm);
*pvmm = vmm;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
index 42ad326521a3..5e55ecbd8005 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
@@ -67,6 +67,10 @@ struct nvkm_vmm_desc_func {
nvkm_vmm_pte_func mem;
nvkm_vmm_pte_func dma;
nvkm_vmm_pte_func sgl;
+
+ nvkm_vmm_pte_func pfn;
+ bool (*pfn_clear)(struct nvkm_vmm *, struct nvkm_mmu_pt *, u32 ptei, u32 ptes);
+ nvkm_vmm_pxe_func pfn_unmap;
};
extern const struct nvkm_vmm_desc_func gf100_vmm_pgd;
@@ -141,6 +145,11 @@ struct nvkm_vmm_func {
struct nvkm_vmm_map *);
void (*flush)(struct nvkm_vmm *, int depth);
+ int (*mthd)(struct nvkm_vmm *, struct nvkm_client *,
+ u32 mthd, void *argv, u32 argc);
+
+ void (*invalidate_pdb)(struct nvkm_vmm *, u64 addr);
+
u64 page_block;
const struct nvkm_vmm_page page[];
};
@@ -151,11 +160,12 @@ struct nvkm_vmm_join {
};
int nvkm_vmm_new_(const struct nvkm_vmm_func *, struct nvkm_mmu *,
- u32 pd_header, u64 addr, u64 size, struct lock_class_key *,
- const char *name, struct nvkm_vmm **);
+ u32 pd_header, bool managed, u64 addr, u64 size,
+ struct lock_class_key *, const char *name,
+ struct nvkm_vmm **);
int nvkm_vmm_ctor(const struct nvkm_vmm_func *, struct nvkm_mmu *,
- u32 pd_header, u64 addr, u64 size, struct lock_class_key *,
- const char *name, struct nvkm_vmm *);
+ u32 pd_header, bool managed, u64 addr, u64 size,
+ struct lock_class_key *, const char *name, struct nvkm_vmm *);
struct nvkm_vma *nvkm_vmm_node_search(struct nvkm_vmm *, u64 addr);
struct nvkm_vma *nvkm_vmm_node_split(struct nvkm_vmm *, struct nvkm_vma *,
u64 addr, u64 size);
@@ -163,13 +173,25 @@ int nvkm_vmm_get_locked(struct nvkm_vmm *, bool getref, bool mapref,
bool sparse, u8 page, u8 align, u64 size,
struct nvkm_vma **pvma);
void nvkm_vmm_put_locked(struct nvkm_vmm *, struct nvkm_vma *);
-void nvkm_vmm_unmap_locked(struct nvkm_vmm *, struct nvkm_vma *);
-void nvkm_vmm_unmap_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma);
+void nvkm_vmm_unmap_locked(struct nvkm_vmm *, struct nvkm_vma *, bool pfn);
+void nvkm_vmm_unmap_region(struct nvkm_vmm *, struct nvkm_vma *);
+
+#define NVKM_VMM_PFN_ADDR 0xfffffffffffff000ULL
+#define NVKM_VMM_PFN_ADDR_SHIFT 12
+#define NVKM_VMM_PFN_APER 0x00000000000000f0ULL
+#define NVKM_VMM_PFN_HOST 0x0000000000000000ULL
+#define NVKM_VMM_PFN_VRAM 0x0000000000000010ULL
+#define NVKM_VMM_PFN_W 0x0000000000000002ULL
+#define NVKM_VMM_PFN_V 0x0000000000000001ULL
+#define NVKM_VMM_PFN_NONE 0x0000000000000000ULL
+
+int nvkm_vmm_pfn_map(struct nvkm_vmm *, u8 page, u64 addr, u64 size, u64 *pfn);
+int nvkm_vmm_pfn_unmap(struct nvkm_vmm *, u64 addr, u64 size);
struct nvkm_vma *nvkm_vma_tail(struct nvkm_vma *, u64 tail);
int nv04_vmm_new_(const struct nvkm_vmm_func *, struct nvkm_mmu *, u32,
- u64, u64, void *, u32, struct lock_class_key *,
+ bool, u64, u64, void *, u32, struct lock_class_key *,
const char *, struct nvkm_vmm **);
int nv04_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
@@ -179,70 +201,76 @@ int nv50_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
void nv50_vmm_flush(struct nvkm_vmm *, int);
int gf100_vmm_new_(const struct nvkm_vmm_func *, const struct nvkm_vmm_func *,
- struct nvkm_mmu *, u64, u64, void *, u32,
+ struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
int gf100_vmm_join_(struct nvkm_vmm *, struct nvkm_memory *, u64 base);
int gf100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
void gf100_vmm_part(struct nvkm_vmm *, struct nvkm_memory *);
int gf100_vmm_aper(enum nvkm_memory_target);
int gf100_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
-void gf100_vmm_flush_(struct nvkm_vmm *, int);
void gf100_vmm_flush(struct nvkm_vmm *, int);
+void gf100_vmm_invalidate(struct nvkm_vmm *, u32 type);
+void gf100_vmm_invalidate_pdb(struct nvkm_vmm *, u64 addr);
int gk20a_vmm_aper(enum nvkm_memory_target);
int gm200_vmm_new_(const struct nvkm_vmm_func *, const struct nvkm_vmm_func *,
- struct nvkm_mmu *, u64, u64, void *, u32,
+ struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
int gm200_vmm_join_(struct nvkm_vmm *, struct nvkm_memory *, u64 base);
int gm200_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
+int gp100_vmm_new_(const struct nvkm_vmm_func *,
+ struct nvkm_mmu *, bool, u64, u64, void *, u32,
+ struct lock_class_key *, const char *, struct nvkm_vmm **);
int gp100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
int gp100_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
void gp100_vmm_flush(struct nvkm_vmm *, int);
+int gp100_vmm_mthd(struct nvkm_vmm *, struct nvkm_client *, u32, void *, u32);
+void gp100_vmm_invalidate_pdb(struct nvkm_vmm *, u64 addr);
int gv100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
-int nv04_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int nv04_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int nv41_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int nv41_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int nv44_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int nv44_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int nv50_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int nv50_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int mcp77_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int mcp77_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int g84_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int g84_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int gf100_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gf100_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int gk104_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gk104_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int gk20a_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gk20a_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *, struct nvkm_vmm **);
-int gm200_vmm_new_fixed(struct nvkm_mmu *, u64, u64, void *, u32,
+int gm200_vmm_new_fixed(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gm200_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gm200_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gm20b_vmm_new_fixed(struct nvkm_mmu *, u64, u64, void *, u32,
+int gm20b_vmm_new_fixed(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gm20b_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gm20b_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gp100_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gp100_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gp10b_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gp10b_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int gv100_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int gv100_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
-int tu104_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+int tu102_vmm_new(struct nvkm_mmu *, bool, u64, u64, void *, u32,
struct lock_class_key *, const char *,
struct nvkm_vmm **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
index faf5a7e9265e..ab6424faf84c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
@@ -178,15 +178,19 @@ gf100_vmm_desc_16_16[] = {
};
void
-gf100_vmm_flush_(struct nvkm_vmm *vmm, int depth)
+gf100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr)
+{
+ struct nvkm_device *device = vmm->mmu->subdev.device;
+ nvkm_wr32(device, 0x100cb8, addr);
+}
+
+void
+gf100_vmm_invalidate(struct nvkm_vmm *vmm, u32 type)
{
struct nvkm_subdev *subdev = &vmm->mmu->subdev;
struct nvkm_device *device = subdev->device;
- u32 type = depth << 24;
-
- type = 0x00000001; /* PAGE_ALL */
- if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
- type |= 0x00000004; /* HUB_ONLY */
+ struct nvkm_mmu_pt *pd = vmm->pd->pt[0];
+ u64 addr = 0;
mutex_lock(&subdev->mutex);
/* Looks like maybe a "free flush slots" counter, the
@@ -197,7 +201,20 @@ gf100_vmm_flush_(struct nvkm_vmm *vmm, int depth)
break;
);
- nvkm_wr32(device, 0x100cb8, vmm->pd->pt[0]->addr >> 8);
+ if (!(type & 0x00000002) /* ALL_PDB. */) {
+ switch (nvkm_memory_target(pd->memory)) {
+ case NVKM_MEM_TARGET_VRAM: addr |= 0x00000000; break;
+ case NVKM_MEM_TARGET_HOST: addr |= 0x00000002; break;
+ case NVKM_MEM_TARGET_NCOH: addr |= 0x00000003; break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ addr |= (vmm->pd->pt[0]->addr >> 12) << 4;
+
+ vmm->func->invalidate_pdb(vmm, addr);
+ }
+
nvkm_wr32(device, 0x100cbc, 0x80000000 | type);
/* Wait for flush to be queued? */
@@ -211,7 +228,10 @@ gf100_vmm_flush_(struct nvkm_vmm *vmm, int depth)
void
gf100_vmm_flush(struct nvkm_vmm *vmm, int depth)
{
- gf100_vmm_flush_(vmm, 0);
+ u32 type = 0x00000001; /* PAGE_ALL */
+ if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
+ type |= 0x00000004; /* HUB_ONLY */
+ gf100_vmm_invalidate(vmm, type);
}
int
@@ -354,6 +374,7 @@ gf100_vmm_17 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 17, &gf100_vmm_desc_17_17[0], NVKM_VMM_PAGE_xVxC },
{ 12, &gf100_vmm_desc_17_12[0], NVKM_VMM_PAGE_xVHx },
@@ -368,6 +389,7 @@ gf100_vmm_16 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 16, &gf100_vmm_desc_16_16[0], NVKM_VMM_PAGE_xVxC },
{ 12, &gf100_vmm_desc_16_12[0], NVKM_VMM_PAGE_xVHx },
@@ -378,14 +400,14 @@ gf100_vmm_16 = {
int
gf100_vmm_new_(const struct nvkm_vmm_func *func_16,
const struct nvkm_vmm_func *func_17,
- struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+ struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
switch (mmu->subdev.device->fb->page) {
- case 16: return nv04_vmm_new_(func_16, mmu, 0, addr, size,
+ case 16: return nv04_vmm_new_(func_16, mmu, 0, managed, addr, size,
argv, argc, key, name, pvmm);
- case 17: return nv04_vmm_new_(func_17, mmu, 0, addr, size,
+ case 17: return nv04_vmm_new_(func_17, mmu, 0, managed, addr, size,
argv, argc, key, name, pvmm);
default:
WARN_ON(1);
@@ -394,10 +416,10 @@ gf100_vmm_new_(const struct nvkm_vmm_func *func_16,
}
int
-gf100_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gf100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return gf100_vmm_new_(&gf100_vmm_16, &gf100_vmm_17, mmu, addr,
+ return gf100_vmm_new_(&gf100_vmm_16, &gf100_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk104.c
index 0ebb7bccfcd2..0b59c01fd146 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk104.c
@@ -71,6 +71,7 @@ gk104_vmm_17 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 17, &gk104_vmm_desc_17_17[0], NVKM_VMM_PAGE_xVxC },
{ 12, &gk104_vmm_desc_17_12[0], NVKM_VMM_PAGE_xVHx },
@@ -85,6 +86,7 @@ gk104_vmm_16 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 16, &gk104_vmm_desc_16_16[0], NVKM_VMM_PAGE_xVxC },
{ 12, &gk104_vmm_desc_16_12[0], NVKM_VMM_PAGE_xVHx },
@@ -93,10 +95,10 @@ gk104_vmm_16 = {
};
int
-gk104_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gk104_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return gf100_vmm_new_(&gk104_vmm_16, &gk104_vmm_17, mmu, addr,
+ return gf100_vmm_new_(&gk104_vmm_16, &gk104_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk20a.c
index 8086994a0446..5a9582dce970 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgk20a.c
@@ -40,6 +40,7 @@ gk20a_vmm_17 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 17, &gk104_vmm_desc_17_17[0], NVKM_VMM_PAGE_xxHC },
{ 12, &gk104_vmm_desc_17_12[0], NVKM_VMM_PAGE_xxHx },
@@ -54,6 +55,7 @@ gk20a_vmm_16 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 16, &gk104_vmm_desc_16_16[0], NVKM_VMM_PAGE_xxHC },
{ 12, &gk104_vmm_desc_16_12[0], NVKM_VMM_PAGE_xxHx },
@@ -62,10 +64,10 @@ gk20a_vmm_16 = {
};
int
-gk20a_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gk20a_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return gf100_vmm_new_(&gk20a_vmm_16, &gk20a_vmm_17, mmu, addr,
+ return gf100_vmm_new_(&gk20a_vmm_16, &gk20a_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm200.c
index a1676a4644fe..2e61af02d4d8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm200.c
@@ -113,6 +113,7 @@ gm200_vmm_17 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 27, &gm200_vmm_desc_17_17[1], NVKM_VMM_PAGE_Sxxx },
{ 17, &gm200_vmm_desc_17_17[0], NVKM_VMM_PAGE_SVxC },
@@ -128,6 +129,7 @@ gm200_vmm_16 = {
.aper = gf100_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 27, &gm200_vmm_desc_16_16[1], NVKM_VMM_PAGE_Sxxx },
{ 16, &gm200_vmm_desc_16_16[0], NVKM_VMM_PAGE_SVxC },
@@ -139,9 +141,9 @@ gm200_vmm_16 = {
int
gm200_vmm_new_(const struct nvkm_vmm_func *func_16,
const struct nvkm_vmm_func *func_17,
- struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+ struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
const struct nvkm_vmm_func *func;
union {
@@ -163,23 +165,23 @@ gm200_vmm_new_(const struct nvkm_vmm_func *func_16,
} else
return ret;
- return nvkm_vmm_new_(func, mmu, 0, addr, size, key, name, pvmm);
+ return nvkm_vmm_new_(func, mmu, 0, managed, addr, size, key, name, pvmm);
}
int
-gm200_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gm200_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return gm200_vmm_new_(&gm200_vmm_16, &gm200_vmm_17, mmu, addr,
+ return gm200_vmm_new_(&gm200_vmm_16, &gm200_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
int
-gm200_vmm_new_fixed(struct nvkm_mmu *mmu, u64 addr, u64 size,
+gm200_vmm_new_fixed(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
void *argv, u32 argc, struct lock_class_key *key,
const char *name, struct nvkm_vmm **pvmm)
{
- return gf100_vmm_new_(&gm200_vmm_16, &gm200_vmm_17, mmu, addr,
+ return gf100_vmm_new_(&gm200_vmm_16, &gm200_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm20b.c
index 64d4b6cff8dd..96b759695dd8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgm20b.c
@@ -28,6 +28,7 @@ gm20b_vmm_17 = {
.aper = gk20a_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 27, &gm200_vmm_desc_17_17[1], NVKM_VMM_PAGE_Sxxx },
{ 17, &gm200_vmm_desc_17_17[0], NVKM_VMM_PAGE_SxHC },
@@ -43,6 +44,7 @@ gm20b_vmm_16 = {
.aper = gk20a_vmm_aper,
.valid = gf100_vmm_valid,
.flush = gf100_vmm_flush,
+ .invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
{ 27, &gm200_vmm_desc_16_16[1], NVKM_VMM_PAGE_Sxxx },
{ 16, &gm200_vmm_desc_16_16[0], NVKM_VMM_PAGE_SxHC },
@@ -52,19 +54,19 @@ gm20b_vmm_16 = {
};
int
-gm20b_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gm20b_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return gm200_vmm_new_(&gm20b_vmm_16, &gm20b_vmm_17, mmu, addr,
+ return gm200_vmm_new_(&gm20b_vmm_16, &gm20b_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
int
-gm20b_vmm_new_fixed(struct nvkm_mmu *mmu, u64 addr, u64 size,
+gm20b_vmm_new_fixed(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
void *argv, u32 argc, struct lock_class_key *key,
const char *name, struct nvkm_vmm **pvmm)
{
- return gf100_vmm_new_(&gm20b_vmm_16, &gm20b_vmm_17, mmu, addr,
+ return gf100_vmm_new_(&gm20b_vmm_16, &gm20b_vmm_17, mmu, managed, addr,
size, argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
index 059fafe0e771..b4f519768d5e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
@@ -21,12 +21,90 @@
*/
#include "vmm.h"
+#include <core/client.h>
#include <subdev/fb.h>
#include <subdev/ltc.h>
+#include <subdev/timer.h>
+#include <engine/gr.h>
#include <nvif/ifc00d.h>
#include <nvif/unpack.h>
+static void
+gp100_vmm_pfn_unmap(struct nvkm_vmm *vmm,
+ struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
+{
+ struct device *dev = vmm->mmu->subdev.device->dev;
+ dma_addr_t addr;
+
+ nvkm_kmap(pt->memory);
+ while (ptes--) {
+ u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0);
+ u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4);
+ u64 data = (u64)datahi << 32 | datalo;
+ if ((data & (3ULL << 1)) != 0) {
+ addr = (data >> 8) << 12;
+ dma_unmap_page(dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ }
+ ptei++;
+ }
+ nvkm_done(pt->memory);
+}
+
+static bool
+gp100_vmm_pfn_clear(struct nvkm_vmm *vmm,
+ struct nvkm_mmu_pt *pt, u32 ptei, u32 ptes)
+{
+ bool dma = false;
+ nvkm_kmap(pt->memory);
+ while (ptes--) {
+ u32 datalo = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 0);
+ u32 datahi = nvkm_ro32(pt->memory, pt->base + ptei * 8 + 4);
+ u64 data = (u64)datahi << 32 | datalo;
+ if ((data & BIT_ULL(0)) && (data & (3ULL << 1)) != 0) {
+ VMM_WO064(pt, vmm, ptei * 8, data & ~BIT_ULL(0));
+ dma = true;
+ }
+ ptei++;
+ }
+ nvkm_done(pt->memory);
+ return dma;
+}
+
+static void
+gp100_vmm_pgt_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
+ u32 ptei, u32 ptes, struct nvkm_vmm_map *map)
+{
+ struct device *dev = vmm->mmu->subdev.device->dev;
+ dma_addr_t addr;
+
+ nvkm_kmap(pt->memory);
+ while (ptes--) {
+ u64 data = 0;
+ if (!(*map->pfn & NVKM_VMM_PFN_W))
+ data |= BIT_ULL(6); /* RO. */
+
+ if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
+ addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
+ addr = dma_map_page(dev, pfn_to_page(addr), 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ if (!WARN_ON(dma_mapping_error(dev, addr))) {
+ data |= addr >> 4;
+ data |= 2ULL << 1; /* SYSTEM_COHERENT_MEMORY. */
+ data |= BIT_ULL(3); /* VOL. */
+ data |= BIT_ULL(0); /* VALID. */
+ }
+ } else {
+ data |= (*map->pfn & NVKM_VMM_PFN_ADDR) >> 4;
+ data |= BIT_ULL(0); /* VALID. */
+ }
+
+ VMM_WO064(pt, vmm, ptei++ * 8, data);
+ map->pfn++;
+ }
+ nvkm_done(pt->memory);
+}
+
static inline void
gp100_vmm_pgt_pte(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
u32 ptei, u32 ptes, struct nvkm_vmm_map *map, u64 addr)
@@ -89,6 +167,9 @@ gp100_vmm_desc_spt = {
.mem = gp100_vmm_pgt_mem,
.dma = gp100_vmm_pgt_dma,
.sgl = gp100_vmm_pgt_sgl,
+ .pfn = gp100_vmm_pgt_pfn,
+ .pfn_clear = gp100_vmm_pfn_clear,
+ .pfn_unmap = gp100_vmm_pfn_unmap,
};
static void
@@ -306,16 +387,100 @@ gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
return 0;
}
+static int
+gp100_vmm_fault_cancel(struct nvkm_vmm *vmm, void *argv, u32 argc)
+{
+ struct nvkm_device *device = vmm->mmu->subdev.device;
+ union {
+ struct gp100_vmm_fault_cancel_v0 v0;
+ } *args = argv;
+ int ret = -ENOSYS;
+ u32 inst, aper;
+
+ if ((ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false)))
+ return ret;
+
+ /* Translate MaxwellFaultBufferA instance pointer to the same
+ * format as the NV_GR_FECS_CURRENT_CTX register.
+ */
+ aper = (args->v0.inst >> 8) & 3;
+ args->v0.inst >>= 12;
+ args->v0.inst |= aper << 28;
+ args->v0.inst |= 0x80000000;
+
+ if (!WARN_ON(nvkm_gr_ctxsw_pause(device))) {
+ if ((inst = nvkm_gr_ctxsw_inst(device)) == args->v0.inst) {
+ gf100_vmm_invalidate(vmm, 0x0000001b
+ /* CANCEL_TARGETED. */ |
+ (args->v0.hub << 20) |
+ (args->v0.gpc << 15) |
+ (args->v0.client << 9));
+ }
+ WARN_ON(nvkm_gr_ctxsw_resume(device));
+ }
+
+ return 0;
+}
+
+static int
+gp100_vmm_fault_replay(struct nvkm_vmm *vmm, void *argv, u32 argc)
+{
+ union {
+ struct gp100_vmm_fault_replay_vn vn;
+ } *args = argv;
+ int ret = -ENOSYS;
+
+ if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) {
+ gf100_vmm_invalidate(vmm, 0x0000000b); /* REPLAY_GLOBAL. */
+ }
+
+ return ret;
+}
+
+int
+gp100_vmm_mthd(struct nvkm_vmm *vmm,
+ struct nvkm_client *client, u32 mthd, void *argv, u32 argc)
+{
+ if (client->super) {
+ switch (mthd) {
+ case GP100_VMM_VN_FAULT_REPLAY:
+ return gp100_vmm_fault_replay(vmm, argv, argc);
+ case GP100_VMM_VN_FAULT_CANCEL:
+ return gp100_vmm_fault_cancel(vmm, argv, argc);
+ default:
+ break;
+ }
+ }
+ return -EINVAL;
+}
+
+void
+gp100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr)
+{
+ struct nvkm_device *device = vmm->mmu->subdev.device;
+ nvkm_wr32(device, 0x100cb8, lower_32_bits(addr));
+ nvkm_wr32(device, 0x100cec, upper_32_bits(addr));
+}
+
void
gp100_vmm_flush(struct nvkm_vmm *vmm, int depth)
{
- gf100_vmm_flush_(vmm, 5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth);
+ u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24;
+ type = 0; /*XXX: need to confirm stuff works with depth enabled... */
+ if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
+ type |= 0x00000004; /* HUB_ONLY */
+ type |= 0x00000001; /* PAGE_ALL */
+ gf100_vmm_invalidate(vmm, type);
}
int
gp100_vmm_join(struct nvkm_vmm *vmm, struct nvkm_memory *inst)
{
- const u64 base = BIT_ULL(10) /* VER2 */ | BIT_ULL(11); /* 64KiB */
+ u64 base = BIT_ULL(10) /* VER2 */ | BIT_ULL(11) /* 64KiB */;
+ if (vmm->replay) {
+ base |= BIT_ULL(4); /* FAULT_REPLAY_TEX */
+ base |= BIT_ULL(5); /* FAULT_REPLAY_GCC */
+ }
return gf100_vmm_join_(vmm, inst, base);
}
@@ -326,6 +491,8 @@ gp100_vmm = {
.aper = gf100_vmm_aper,
.valid = gp100_vmm_valid,
.flush = gp100_vmm_flush,
+ .mthd = gp100_vmm_mthd,
+ .invalidate_pdb = gp100_vmm_invalidate_pdb,
.page = {
{ 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
{ 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
@@ -338,10 +505,39 @@ gp100_vmm = {
};
int
-gp100_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gp100_vmm_new_(const struct nvkm_vmm_func *func,
+ struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
+{
+ union {
+ struct gp100_vmm_vn vn;
+ struct gp100_vmm_v0 v0;
+ } *args = argv;
+ int ret = -ENOSYS;
+ bool replay;
+
+ if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
+ replay = args->v0.fault_replay != 0;
+ } else
+ if (!(ret = nvif_unvers(ret, &argv, &argc, args->vn))) {
+ replay = false;
+ } else
+ return ret;
+
+ ret = nvkm_vmm_new_(func, mmu, 0, managed, addr, size, key, name, pvmm);
+ if (ret)
+ return ret;
+
+ (*pvmm)->replay = replay;
+ return 0;
+}
+
+int
+gp100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&gp100_vmm, mmu, 0, addr, size,
- argv, argc, key, name, pvmm);
+ return gp100_vmm_new_(&gp100_vmm, mmu, managed, addr, size,
+ argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp10b.c
index 3dcc6bddb32f..e081239afe58 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp10b.c
@@ -28,6 +28,8 @@ gp10b_vmm = {
.aper = gk20a_vmm_aper,
.valid = gp100_vmm_valid,
.flush = gp100_vmm_flush,
+ .mthd = gp100_vmm_mthd,
+ .invalidate_pdb = gp100_vmm_invalidate_pdb,
.page = {
{ 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
{ 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
@@ -40,10 +42,10 @@ gp10b_vmm = {
};
int
-gp10b_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gp10b_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&gp10b_vmm, mmu, 0, addr, size,
- argv, argc, key, name, pvmm);
+ return gp100_vmm_new_(&gp10b_vmm, mmu, managed, addr, size,
+ argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgv100.c
index 2fa40c16e6d2..f0e21f63253a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgv100.c
@@ -66,6 +66,8 @@ gv100_vmm = {
.aper = gf100_vmm_aper,
.valid = gp100_vmm_valid,
.flush = gp100_vmm_flush,
+ .mthd = gp100_vmm_mthd,
+ .invalidate_pdb = gp100_vmm_invalidate_pdb,
.page = {
{ 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
{ 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
@@ -78,10 +80,10 @@ gv100_vmm = {
};
int
-gv100_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+gv100_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&gv100_vmm, mmu, 0, addr, size,
- argv, argc, key, name, pvmm);
+ return gp100_vmm_new_(&gv100_vmm, mmu, managed, addr, size,
+ argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmmcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmmcp77.c
index e63d984cbfd4..bdddd99f5877 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmmcp77.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmmcp77.c
@@ -36,10 +36,10 @@ mcp77_vmm = {
};
int
-mcp77_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+mcp77_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&mcp77_vmm, mmu, 0, addr, size,
+ return nv04_vmm_new_(&mcp77_vmm, mmu, 0, managed, addr, size,
argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv04.c
index 0cab1ffc9f64..4c6b3b7d221f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv04.c
@@ -100,16 +100,17 @@ nv04_vmm = {
int
nv04_vmm_new_(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
- u32 pd_header, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
- struct nvkm_vmm **pvmm)
+ u32 pd_header, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key,
+ const char *name, struct nvkm_vmm **pvmm)
{
union {
struct nv04_vmm_vn vn;
} *args = argv;
int ret;
- ret = nvkm_vmm_new_(func, mmu, pd_header, addr, size, key, name, pvmm);
+ ret = nvkm_vmm_new_(func, mmu, pd_header, managed, addr, size,
+ key, name, pvmm);
if (ret)
return ret;
@@ -117,15 +118,15 @@ nv04_vmm_new_(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
}
int
-nv04_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
+nv04_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key, const char *name,
struct nvkm_vmm **pvmm)
{
struct nvkm_memory *mem;
struct nvkm_vmm *vmm;
int ret;
- ret = nv04_vmm_new_(&nv04_vmm, mmu, 8, addr, size,
+ ret = nv04_vmm_new_(&nv04_vmm, mmu, 8, managed, addr, size,
argv, argc, key, name, &vmm);
*pvmm = vmm;
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv41.c
index b595f130e573..1d3369683a21 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv41.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv41.c
@@ -104,10 +104,10 @@ nv41_vmm = {
};
int
-nv41_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
+nv41_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key, const char *name,
struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&nv41_vmm, mmu, 0, addr, size,
+ return nv04_vmm_new_(&nv41_vmm, mmu, 0, managed, addr, size,
argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c
index b834e4352334..a82936ba9890 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c
@@ -205,15 +205,15 @@ nv44_vmm = {
};
int
-nv44_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
+nv44_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key, const char *name,
struct nvkm_vmm **pvmm)
{
struct nvkm_subdev *subdev = &mmu->subdev;
struct nvkm_vmm *vmm;
int ret;
- ret = nv04_vmm_new_(&nv44_vmm, mmu, 0, addr, size,
+ ret = nv04_vmm_new_(&nv44_vmm, mmu, 0, managed, addr, size,
argv, argc, key, name, &vmm);
*pvmm = vmm;
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
index 64f75d906202..c98afe3134ee 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
@@ -376,10 +376,10 @@ nv50_vmm = {
};
int
-nv50_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size, void *argv, u32 argc,
- struct lock_class_key *key, const char *name,
+nv50_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
+ void *argv, u32 argc, struct lock_class_key *key, const char *name,
struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&nv50_vmm, mmu, 0, addr, size,
+ return nv04_vmm_new_(&nv50_vmm, mmu, 0, managed, addr, size,
argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
index adaadd92110f..be91cffc3b52 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
@@ -24,7 +24,7 @@
#include <subdev/timer.h>
static void
-tu104_vmm_flush(struct nvkm_vmm *vmm, int depth)
+tu102_vmm_flush(struct nvkm_vmm *vmm, int depth)
{
struct nvkm_subdev *subdev = &vmm->mmu->subdev;
struct nvkm_device *device = subdev->device;
@@ -50,12 +50,13 @@ tu104_vmm_flush(struct nvkm_vmm *vmm, int depth)
}
static const struct nvkm_vmm_func
-tu104_vmm = {
+tu102_vmm = {
.join = gv100_vmm_join,
.part = gf100_vmm_part,
.aper = gf100_vmm_aper,
.valid = gp100_vmm_valid,
- .flush = tu104_vmm_flush,
+ .flush = tu102_vmm_flush,
+ .mthd = gp100_vmm_mthd,
.page = {
{ 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
{ 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
@@ -68,10 +69,10 @@ tu104_vmm = {
};
int
-tu104_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size,
+tu102_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
void *argv, u32 argc, struct lock_class_key *key,
const char *name, struct nvkm_vmm **pvmm)
{
- return nv04_vmm_new_(&tu104_vmm, mmu, 0, addr, size,
- argv, argc, key, name, pvmm);
+ return gp100_vmm_new_(&tu102_vmm, mmu, managed, addr, size,
+ argv, argc, key, name, pvmm);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
index 11b28b086a06..7b052879af72 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
@@ -88,10 +88,10 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec)
if (exec) {
nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC,
memx->base, finish);
+ nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n",
+ reply[0], reply[1]);
}
- nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n",
- reply[0], reply[1]);
kfree(memx);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
index 5c14d6ac855d..1df09ed6fe6d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
@@ -853,7 +853,7 @@ acr_r352_shutdown(struct acr_r352 *acr, struct nvkm_secboot *sb)
* and the expected behavior on RM as well
*/
if (ret && ret != 0x1d) {
- nvkm_error(subdev, "HS unload failed, ret 0x%08x", ret);
+ nvkm_error(subdev, "HS unload failed, ret 0x%08x\n", ret);
return -EINVAL;
}
nvkm_debug(subdev, "HS unload blob completed\n");
@@ -922,7 +922,7 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
if (ret < 0) {
return ret;
} else if (ret > 0) {
- nvkm_error(subdev, "HS load failed, ret 0x%08x", ret);
+ nvkm_error(subdev, "HS load failed, ret 0x%08x\n", ret);
return -EINVAL;
}
nvkm_debug(subdev, "HS load blob completed\n");
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
index 3695cde669f8..07914e36939e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -132,11 +132,12 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode)
duty = nvkm_therm_update_linear(therm);
break;
case NVBIOS_THERM_FAN_OTHER:
- if (therm->cstate)
+ if (therm->cstate) {
duty = therm->cstate;
- else
+ poll = false;
+ } else {
duty = nvkm_therm_update_linear_fallback(therm);
- poll = false;
+ }
break;
}
immd = false;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
index 67ada1d9a28c..cce6e4e90ebf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c
@@ -41,6 +41,22 @@ nvkm_top_device_new(struct nvkm_top *top)
}
u32
+nvkm_top_addr(struct nvkm_device *device, enum nvkm_devidx index)
+{
+ struct nvkm_top *top = device->top;
+ struct nvkm_top_device *info;
+
+ if (top) {
+ list_for_each_entry(info, &top->device, head) {
+ if (info->index == index)
+ return info->addr;
+ }
+ }
+
+ return 0;
+}
+
+u32
nvkm_top_reset(struct nvkm_device *device, enum nvkm_devidx index)
{
struct nvkm_top *top = device->top;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
index 39081eadfd84..e01746ce9fc4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
@@ -73,6 +73,7 @@ gk104_top_oneinit(struct nvkm_top *top)
#define A_(A) if (inst == 0) info->index = NVKM_ENGINE_##A
#define B_(A) if (inst + NVKM_ENGINE_##A##0 < NVKM_ENGINE_##A##_LAST + 1) \
info->index = NVKM_ENGINE_##A##0 + inst
+#define C_(A) if (inst == 0) info->index = NVKM_SUBDEV_##A
switch (type) {
case 0x00000000: A_(GR ); break;
case 0x00000001: A_(CE0 ); break;
@@ -88,6 +89,7 @@ gk104_top_oneinit(struct nvkm_top *top)
case 0x0000000f: A_(NVENC1); break;
case 0x00000010: B_(NVDEC ); break;
case 0x00000013: B_(CE ); break;
+ case 0x00000014: C_(GSP ); break;
break;
default:
break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
index bcd179ba11d0..146adcdd316a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
@@ -2,6 +2,7 @@ nvkm-y += nvkm/subdev/volt/base.o
nvkm-y += nvkm/subdev/volt/gpio.o
nvkm-y += nvkm/subdev/volt/nv40.o
nvkm-y += nvkm/subdev/volt/gf100.o
+nvkm-y += nvkm/subdev/volt/gf117.o
nvkm-y += nvkm/subdev/volt/gk104.o
nvkm-y += nvkm/subdev/volt/gk20a.o
nvkm-y += nvkm/subdev/volt/gm20b.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c
new file mode 100644
index 000000000000..547a58f0aeac
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf117.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ilia Mirkin
+ */
+#include "priv.h"
+
+#include <subdev/fuse.h>
+
+static int
+gf117_volt_speedo_read(struct nvkm_volt *volt)
+{
+ struct nvkm_device *device = volt->subdev.device;
+ struct nvkm_fuse *fuse = device->fuse;
+
+ if (!fuse)
+ return -EINVAL;
+
+ return nvkm_fuse_read(fuse, 0x3a8);
+}
+
+static const struct nvkm_volt_func
+gf117_volt = {
+ .oneinit = gf100_volt_oneinit,
+ .vid_get = nvkm_voltgpio_get,
+ .vid_set = nvkm_voltgpio_set,
+ .speedo_read = gf117_volt_speedo_read,
+};
+
+int
+gf117_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt)
+{
+ struct nvkm_volt *volt;
+ int ret;
+
+ ret = nvkm_volt_new_(&gf117_volt, device, index, &volt);
+ *pvolt = volt;
+ if (ret)
+ return ret;
+
+ return nvkm_voltgpio_init(volt);
+}
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index 00a9c2ab9e6c..64fb788b6647 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -1406,7 +1406,7 @@ static void dsi_pll_disable(struct dss_pll *pll)
static int dsi_dump_dsi_clocks(struct seq_file *s, void *p)
{
- struct dsi_data *dsi = p;
+ struct dsi_data *dsi = s->private;
struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
enum dss_clk_source dispc_clk_src, dsi_clk_src;
int dsi_module = dsi->module_id;
@@ -1467,7 +1467,7 @@ static int dsi_dump_dsi_clocks(struct seq_file *s, void *p)
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
{
- struct dsi_data *dsi = p;
+ struct dsi_data *dsi = s->private;
unsigned long flags;
struct dsi_irq_stats stats;
@@ -1558,7 +1558,7 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
static int dsi_dump_dsi_regs(struct seq_file *s, void *p)
{
- struct dsi_data *dsi = p;
+ struct dsi_data *dsi = s->private;
if (dsi_runtime_get(dsi))
return 0;
@@ -4751,6 +4751,17 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
dsi->vm.flags |= DISPLAY_FLAGS_HSYNC_HIGH;
dsi->vm.flags &= ~DISPLAY_FLAGS_VSYNC_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+ /*
+ * HACK: These flags should be handled through the omap_dss_device bus
+ * flags, but this will only be possible when the DSI encoder will be
+ * converted to the omapdrm-managed encoder model.
+ */
+ dsi->vm.flags &= ~DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+ dsi->vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+ dsi->vm.flags &= ~DISPLAY_FLAGS_DE_LOW;
+ dsi->vm.flags |= DISPLAY_FLAGS_DE_HIGH;
+ dsi->vm.flags &= ~DISPLAY_FLAGS_SYNC_POSEDGE;
+ dsi->vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
dss_mgr_set_timings(&dsi->output, &dsi->vm);
@@ -5083,15 +5094,15 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
snprintf(name, sizeof(name), "dsi%u_regs", dsi->module_id + 1);
dsi->debugfs.regs = dss_debugfs_create_file(dss, name,
- dsi_dump_dsi_regs, &dsi);
+ dsi_dump_dsi_regs, dsi);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
snprintf(name, sizeof(name), "dsi%u_irqs", dsi->module_id + 1);
dsi->debugfs.irqs = dss_debugfs_create_file(dss, name,
- dsi_dump_dsi_irqs, &dsi);
+ dsi_dump_dsi_irqs, dsi);
#endif
snprintf(name, sizeof(name), "dsi%u_clks", dsi->module_id + 1);
dsi->debugfs.clks = dss_debugfs_create_file(dss, name,
- dsi_dump_dsi_clocks, &dsi);
+ dsi_dump_dsi_clocks, dsi);
return 0;
}
@@ -5104,8 +5115,6 @@ static void dsi_unbind(struct device *dev, struct device *master, void *data)
dss_debugfs_remove_file(dsi->debugfs.irqs);
dss_debugfs_remove_file(dsi->debugfs.regs);
- of_platform_depopulate(dev);
-
WARN_ON(dsi->scp_clk_refcount > 0);
dss_pll_unregister(&dsi->pll);
@@ -5457,6 +5466,8 @@ static int dsi_remove(struct platform_device *pdev)
dsi_uninit_output(dsi);
+ of_platform_depopulate(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index 874d8f3cbff6..9da94d10782a 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -17,7 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "omap_drv.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 40acf4ce7c9f..d99e24dcc0bf 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -18,7 +18,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_mode.h>
#include <drm/drm_plane_helper.h>
#include <linux/math64.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 5e67d58cbc28..f8292278f57d 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -21,8 +21,8 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include "omap_dmm_tiler.h"
#include "omap_drv.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index bd7f2c227a25..0c57d2814c51 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -23,7 +23,6 @@
#include <linux/workqueue.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem.h>
#include <drm/omap_drm.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 148b6b20274f..0d85b3a35767 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -18,7 +18,7 @@
#include <linux/list.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_edid.h>
#include "omap_drv.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 4d264fd554d8..4f8eb9d08f99 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -18,7 +18,7 @@
#include <linux/seq_file.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include "omap_dmm_tiler.h"
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index a71f44191273..3e070153ef21 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -77,6 +77,17 @@ config DRM_PANEL_JDI_LT070ME05000
The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses
24 bit per pixel.
+config DRM_PANEL_KINGDISPLAY_KD097D04
+ tristate "Kingdisplay kd097d04 panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Kingdisplay kd097d04
+ TFT-LCD modules. The panel has a 1536x2048 resolution and uses
+ 24 bit RGB per pixel. It provides a MIPI DSI interface to
+ the host and has a built-in LED backlight.
+
config DRM_PANEL_SAMSUNG_LD9040
tristate "Samsung LD9040 RGB/SPI panel"
depends on OF && SPI
@@ -196,6 +207,16 @@ config DRM_PANEL_SHARP_LS043T1LE01
Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
(540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
+config DRM_PANEL_SITRONIX_ST7701
+ tristate "Sitronix ST7701 panel driver"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for the Sitronix
+ ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI
+ system interfaces.
+
config DRM_PANEL_SITRONIX_ST7789V
tristate "Sitronix ST7789V panel"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index cd14ca39c6e0..e7ab71968bbf 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
+obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
+obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o
obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
new file mode 100644
index 000000000000..2a25a914d09e
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct kingdisplay_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *link;
+
+ struct backlight_device *backlight;
+ struct regulator *supply;
+ struct gpio_desc *enable_gpio;
+
+ bool prepared;
+ bool enabled;
+};
+
+struct kingdisplay_panel_cmd {
+ char cmd;
+ char data;
+};
+
+/*
+ * According to the discussion on
+ * https://review.coreboot.org/#/c/coreboot/+/22472/
+ * the panel init array is not part of the panels datasheet but instead
+ * just came in this form from the panel vendor.
+ */
+static const struct kingdisplay_panel_cmd init_code[] = {
+ /* voltage setting */
+ { 0xB0, 0x00 },
+ { 0xB2, 0x02 },
+ { 0xB3, 0x11 },
+ { 0xB4, 0x00 },
+ { 0xB6, 0x80 },
+ /* VCOM disable */
+ { 0xB7, 0x02 },
+ { 0xB8, 0x80 },
+ { 0xBA, 0x43 },
+ /* VCOM setting */
+ { 0xBB, 0x53 },
+ /* VSP setting */
+ { 0xBC, 0x0A },
+ /* VSN setting */
+ { 0xBD, 0x4A },
+ /* VGH setting */
+ { 0xBE, 0x2F },
+ /* VGL setting */
+ { 0xBF, 0x1A },
+ { 0xF0, 0x39 },
+ { 0xF1, 0x22 },
+ /* Gamma setting */
+ { 0xB0, 0x02 },
+ { 0xC0, 0x00 },
+ { 0xC1, 0x01 },
+ { 0xC2, 0x0B },
+ { 0xC3, 0x15 },
+ { 0xC4, 0x22 },
+ { 0xC5, 0x11 },
+ { 0xC6, 0x15 },
+ { 0xC7, 0x19 },
+ { 0xC8, 0x1A },
+ { 0xC9, 0x16 },
+ { 0xCA, 0x18 },
+ { 0xCB, 0x13 },
+ { 0xCC, 0x18 },
+ { 0xCD, 0x13 },
+ { 0xCE, 0x1C },
+ { 0xCF, 0x19 },
+ { 0xD0, 0x21 },
+ { 0xD1, 0x2C },
+ { 0xD2, 0x2F },
+ { 0xD3, 0x30 },
+ { 0xD4, 0x19 },
+ { 0xD5, 0x1F },
+ { 0xD6, 0x00 },
+ { 0xD7, 0x01 },
+ { 0xD8, 0x0B },
+ { 0xD9, 0x15 },
+ { 0xDA, 0x22 },
+ { 0xDB, 0x11 },
+ { 0xDC, 0x15 },
+ { 0xDD, 0x19 },
+ { 0xDE, 0x1A },
+ { 0xDF, 0x16 },
+ { 0xE0, 0x18 },
+ { 0xE1, 0x13 },
+ { 0xE2, 0x18 },
+ { 0xE3, 0x13 },
+ { 0xE4, 0x1C },
+ { 0xE5, 0x19 },
+ { 0xE6, 0x21 },
+ { 0xE7, 0x2C },
+ { 0xE8, 0x2F },
+ { 0xE9, 0x30 },
+ { 0xEA, 0x19 },
+ { 0xEB, 0x1F },
+ /* GOA MUX setting */
+ { 0xB0, 0x01 },
+ { 0xC0, 0x10 },
+ { 0xC1, 0x0F },
+ { 0xC2, 0x0E },
+ { 0xC3, 0x0D },
+ { 0xC4, 0x0C },
+ { 0xC5, 0x0B },
+ { 0xC6, 0x0A },
+ { 0xC7, 0x09 },
+ { 0xC8, 0x08 },
+ { 0xC9, 0x07 },
+ { 0xCA, 0x06 },
+ { 0xCB, 0x05 },
+ { 0xCC, 0x00 },
+ { 0xCD, 0x01 },
+ { 0xCE, 0x02 },
+ { 0xCF, 0x03 },
+ { 0xD0, 0x04 },
+ { 0xD6, 0x10 },
+ { 0xD7, 0x0F },
+ { 0xD8, 0x0E },
+ { 0xD9, 0x0D },
+ { 0xDA, 0x0C },
+ { 0xDB, 0x0B },
+ { 0xDC, 0x0A },
+ { 0xDD, 0x09 },
+ { 0xDE, 0x08 },
+ { 0xDF, 0x07 },
+ { 0xE0, 0x06 },
+ { 0xE1, 0x05 },
+ { 0xE2, 0x00 },
+ { 0xE3, 0x01 },
+ { 0xE4, 0x02 },
+ { 0xE5, 0x03 },
+ { 0xE6, 0x04 },
+ { 0xE7, 0x00 },
+ { 0xEC, 0xC0 },
+ /* GOA timing setting */
+ { 0xB0, 0x03 },
+ { 0xC0, 0x01 },
+ { 0xC2, 0x6F },
+ { 0xC3, 0x6F },
+ { 0xC5, 0x36 },
+ { 0xC8, 0x08 },
+ { 0xC9, 0x04 },
+ { 0xCA, 0x41 },
+ { 0xCC, 0x43 },
+ { 0xCF, 0x60 },
+ { 0xD2, 0x04 },
+ { 0xD3, 0x04 },
+ { 0xD4, 0x03 },
+ { 0xD5, 0x02 },
+ { 0xD6, 0x01 },
+ { 0xD7, 0x00 },
+ { 0xDB, 0x01 },
+ { 0xDE, 0x36 },
+ { 0xE6, 0x6F },
+ { 0xE7, 0x6F },
+ /* GOE setting */
+ { 0xB0, 0x06 },
+ { 0xB8, 0xA5 },
+ { 0xC0, 0xA5 },
+ { 0xD5, 0x3F },
+};
+
+static inline
+struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct kingdisplay_panel, base);
+}
+
+static int kingdisplay_panel_disable(struct drm_panel *panel)
+{
+ struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+ int err;
+
+ if (!kingdisplay->enabled)
+ return 0;
+
+ backlight_disable(kingdisplay->backlight);
+
+ err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
+ if (err < 0)
+ DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
+ err);
+
+ kingdisplay->enabled = false;
+
+ return 0;
+}
+
+static int kingdisplay_panel_unprepare(struct drm_panel *panel)
+{
+ struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+ int err;
+
+ if (!kingdisplay->prepared)
+ return 0;
+
+ err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
+ if (err < 0) {
+ DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
+ err);
+ return err;
+ }
+
+ /* T15: 120ms */
+ msleep(120);
+
+ gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
+
+ err = regulator_disable(kingdisplay->supply);
+ if (err < 0)
+ return err;
+
+ kingdisplay->prepared = false;
+
+ return 0;
+}
+
+static int kingdisplay_panel_prepare(struct drm_panel *panel)
+{
+ struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+ int err, regulator_err;
+ unsigned int i;
+
+ if (kingdisplay->prepared)
+ return 0;
+
+ gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
+
+ err = regulator_enable(kingdisplay->supply);
+ if (err < 0)
+ return err;
+
+ /* T2: 15ms */
+ usleep_range(15000, 16000);
+
+ gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
+
+ /* T4: 15ms */
+ usleep_range(15000, 16000);
+
+ for (i = 0; i < ARRAY_SIZE(init_code); i++) {
+ err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
+ sizeof(struct kingdisplay_panel_cmd));
+ if (err < 0) {
+ DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n",
+ err);
+ goto poweroff;
+ }
+ }
+
+ err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
+ if (err < 0) {
+ DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
+ err);
+ goto poweroff;
+ }
+
+ /* T6: 120ms */
+ msleep(120);
+
+ err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
+ if (err < 0) {
+ DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
+ err);
+ goto poweroff;
+ }
+
+ /* T7: 10ms */
+ usleep_range(10000, 11000);
+
+ kingdisplay->prepared = true;
+
+ return 0;
+
+poweroff:
+ gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
+
+ regulator_err = regulator_disable(kingdisplay->supply);
+ if (regulator_err)
+ DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n",
+ regulator_err);
+
+ return err;
+}
+
+static int kingdisplay_panel_enable(struct drm_panel *panel)
+{
+ struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+ int ret;
+
+ if (kingdisplay->enabled)
+ return 0;
+
+ ret = backlight_enable(kingdisplay->backlight);
+ if (ret) {
+ DRM_DEV_ERROR(panel->drm->dev,
+ "Failed to enable backlight %d\n", ret);
+ return ret;
+ }
+
+ kingdisplay->enabled = true;
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .clock = 229000,
+ .hdisplay = 1536,
+ .hsync_start = 1536 + 100,
+ .hsync_end = 1536 + 100 + 24,
+ .htotal = 1536 + 100 + 24 + 100,
+ .vdisplay = 2048,
+ .vsync_start = 2048 + 95,
+ .vsync_end = 2048 + 95 + 2,
+ .vtotal = 2048 + 95 + 2 + 23,
+ .vrefresh = 60,
+};
+
+static int kingdisplay_panel_get_modes(struct drm_panel *panel)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, &default_mode);
+ if (!mode) {
+ DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ default_mode.vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ drm_mode_probed_add(panel->connector, mode);
+
+ panel->connector->display_info.width_mm = 147;
+ panel->connector->display_info.height_mm = 196;
+ panel->connector->display_info.bpc = 8;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs kingdisplay_panel_funcs = {
+ .disable = kingdisplay_panel_disable,
+ .unprepare = kingdisplay_panel_unprepare,
+ .prepare = kingdisplay_panel_prepare,
+ .enable = kingdisplay_panel_enable,
+ .get_modes = kingdisplay_panel_get_modes,
+};
+
+static const struct of_device_id kingdisplay_of_match[] = {
+ { .compatible = "kingdisplay,kd097d04", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
+
+static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
+{
+ struct device *dev = &kingdisplay->link->dev;
+ int err;
+
+ kingdisplay->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(kingdisplay->supply))
+ return PTR_ERR(kingdisplay->supply);
+
+ kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(kingdisplay->enable_gpio)) {
+ err = PTR_ERR(kingdisplay->enable_gpio);
+ dev_dbg(dev, "failed to get enable gpio: %d\n", err);
+ kingdisplay->enable_gpio = NULL;
+ }
+
+ kingdisplay->backlight = devm_of_find_backlight(dev);
+ if (IS_ERR(kingdisplay->backlight))
+ return PTR_ERR(kingdisplay->backlight);
+
+ drm_panel_init(&kingdisplay->base);
+ kingdisplay->base.funcs = &kingdisplay_panel_funcs;
+ kingdisplay->base.dev = &kingdisplay->link->dev;
+
+ return drm_panel_add(&kingdisplay->base);
+}
+
+static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
+{
+ drm_panel_remove(&kingdisplay->base);
+}
+
+static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
+{
+ struct kingdisplay_panel *kingdisplay;
+ int err;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_LPM;
+
+ kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
+ if (!kingdisplay)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, kingdisplay);
+ kingdisplay->link = dsi;
+
+ err = kingdisplay_panel_add(kingdisplay);
+ if (err < 0)
+ return err;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
+{
+ struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
+ int err;
+
+ err = kingdisplay_panel_unprepare(&kingdisplay->base);
+ if (err < 0)
+ DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
+ err);
+
+ err = kingdisplay_panel_disable(&kingdisplay->base);
+ if (err < 0)
+ DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
+
+ err = mipi_dsi_detach(dsi);
+ if (err < 0)
+ DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
+ err);
+
+ kingdisplay_panel_del(kingdisplay);
+
+ return 0;
+}
+
+static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
+
+ kingdisplay_panel_unprepare(&kingdisplay->base);
+ kingdisplay_panel_disable(&kingdisplay->base);
+}
+
+static struct mipi_dsi_driver kingdisplay_panel_driver = {
+ .driver = {
+ .name = "panel-kingdisplay-kd097d04",
+ .of_match_table = kingdisplay_of_match,
+ },
+ .probe = kingdisplay_panel_probe,
+ .remove = kingdisplay_panel_remove,
+ .shutdown = kingdisplay_panel_shutdown,
+};
+module_mipi_dsi_driver(kingdisplay_panel_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
+MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 9c69e739a524..9e8218f6a3f2 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1597,6 +1597,30 @@ static const struct panel_desc kyo_tcg121xglp = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
};
+static const struct drm_display_mode lemaker_bl035_rgb_002_mode = {
+ .clock = 7000,
+ .hdisplay = 320,
+ .hsync_start = 320 + 20,
+ .hsync_end = 320 + 20 + 30,
+ .htotal = 320 + 20 + 30 + 38,
+ .vdisplay = 240,
+ .vsync_start = 240 + 4,
+ .vsync_end = 240 + 4 + 3,
+ .vtotal = 240 + 4 + 3 + 15,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc lemaker_bl035_rgb_002 = {
+ .modes = &lemaker_bl035_rgb_002_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 70,
+ .height = 52,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_flags = DRM_BUS_FLAG_DE_LOW,
+};
+
static const struct drm_display_mode lg_lb070wv8_mode = {
.clock = 33246,
.hdisplay = 800,
@@ -2008,6 +2032,30 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
};
+static const struct drm_display_mode pda_91_00156_a0_mode = {
+ .clock = 33300,
+ .hdisplay = 800,
+ .hsync_start = 800 + 1,
+ .hsync_end = 800 + 1 + 64,
+ .htotal = 800 + 1 + 64 + 64,
+ .vdisplay = 480,
+ .vsync_start = 480 + 1,
+ .vsync_end = 480 + 1 + 23,
+ .vtotal = 480 + 1 + 23 + 22,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc pda_91_00156_a0 = {
+ .modes = &pda_91_00156_a0_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 152,
+ .height = 91,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+
static const struct drm_display_mode qd43003c0_40_mode = {
.clock = 9000,
.hdisplay = 480,
@@ -2638,6 +2686,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "kyo,tcg121xglp",
.data = &kyo_tcg121xglp,
}, {
+ .compatible = "lemaker,bl035-rgb-002",
+ .data = &lemaker_bl035_rgb_002,
+ }, {
.compatible = "lg,lb070wv8",
.data = &lg_lb070wv8,
}, {
@@ -2686,6 +2737,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "ortustech,com43h4m85ulc",
.data = &ortustech_com43h4m85ulc,
}, {
+ .compatible = "pda,91-00156-a0",
+ .data = &pda_91_00156_a0,
+ }, {
.compatible = "qiaodian,qd43003c0-40",
.data = &qd43003c0_40,
}, {
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
new file mode 100644
index 000000000000..63f9a1c7fb1b
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+/* Command2 BKx selection command */
+#define DSI_CMD2BKX_SEL 0xFF
+
+/* Command2, BK0 commands */
+#define DSI_CMD2_BK0_PVGAMCTRL 0xB0 /* Positive Voltage Gamma Control */
+#define DSI_CMD2_BK0_NVGAMCTRL 0xB1 /* Negative Voltage Gamma Control */
+#define DSI_CMD2_BK0_LNESET 0xC0 /* Display Line setting */
+#define DSI_CMD2_BK0_PORCTRL 0xC1 /* Porch control */
+#define DSI_CMD2_BK0_INVSEL 0xC2 /* Inversion selection, Frame Rate Control */
+
+/* Command2, BK1 commands */
+#define DSI_CMD2_BK1_VRHS 0xB0 /* Vop amplitude setting */
+#define DSI_CMD2_BK1_VCOM 0xB1 /* VCOM amplitude setting */
+#define DSI_CMD2_BK1_VGHSS 0xB2 /* VGH Voltage setting */
+#define DSI_CMD2_BK1_TESTCMD 0xB3 /* TEST Command Setting */
+#define DSI_CMD2_BK1_VGLS 0xB5 /* VGL Voltage setting */
+#define DSI_CMD2_BK1_PWCTLR1 0xB7 /* Power Control 1 */
+#define DSI_CMD2_BK1_PWCTLR2 0xB8 /* Power Control 2 */
+#define DSI_CMD2_BK1_SPD1 0xC1 /* Source pre_drive timing set1 */
+#define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */
+#define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */
+
+/**
+ * Command2 with BK function selection.
+ *
+ * BIT[4, 0]: [CN2, BKXSEL]
+ * 10 = CMD2BK0, Command2 BK0
+ * 11 = CMD2BK1, Command2 BK1
+ * 00 = Command2 disable
+ */
+#define DSI_CMD2BK1_SEL 0x11
+#define DSI_CMD2BK0_SEL 0x10
+#define DSI_CMD2BKX_SEL_NONE 0x00
+
+/* Command2, BK0 bytes */
+#define DSI_LINESET_LINE 0x69
+#define DSI_LINESET_LDE_EN BIT(7)
+#define DSI_LINESET_LINEDELTA GENMASK(1, 0)
+#define DSI_CMD2_BK0_LNESET_B1 DSI_LINESET_LINEDELTA
+#define DSI_CMD2_BK0_LNESET_B0 (DSI_LINESET_LDE_EN | DSI_LINESET_LINE)
+#define DSI_INVSEL_DEFAULT GENMASK(5, 4)
+#define DSI_INVSEL_NLINV GENMASK(2, 0)
+#define DSI_INVSEL_RTNI GENMASK(2, 1)
+#define DSI_CMD2_BK0_INVSEL_B1 DSI_INVSEL_RTNI
+#define DSI_CMD2_BK0_INVSEL_B0 (DSI_INVSEL_DEFAULT | DSI_INVSEL_NLINV)
+#define DSI_CMD2_BK0_PORCTRL_B0(m) ((m)->vtotal - (m)->vsync_end)
+#define DSI_CMD2_BK0_PORCTRL_B1(m) ((m)->vsync_start - (m)->vdisplay)
+
+/* Command2, BK1 bytes */
+#define DSI_CMD2_BK1_VRHA_SET 0x45
+#define DSI_CMD2_BK1_VCOM_SET 0x13
+#define DSI_CMD2_BK1_VGHSS_SET GENMASK(2, 0)
+#define DSI_CMD2_BK1_TESTCMD_VAL BIT(7)
+#define DSI_VGLS_DEFAULT BIT(6)
+#define DSI_VGLS_SEL GENMASK(2, 0)
+#define DSI_CMD2_BK1_VGLS_SET (DSI_VGLS_DEFAULT | DSI_VGLS_SEL)
+#define DSI_PWCTLR1_AP BIT(7) /* Gamma OP bias, max */
+#define DSI_PWCTLR1_APIS BIT(2) /* Source OP input bias, min */
+#define DSI_PWCTLR1_APOS BIT(0) /* Source OP output bias, min */
+#define DSI_CMD2_BK1_PWCTLR1_SET (DSI_PWCTLR1_AP | DSI_PWCTLR1_APIS | \
+ DSI_PWCTLR1_APOS)
+#define DSI_PWCTLR2_AVDD BIT(5) /* AVDD 6.6v */
+#define DSI_PWCTLR2_AVCL 0x0 /* AVCL -4.4v */
+#define DSI_CMD2_BK1_PWCTLR2_SET (DSI_PWCTLR2_AVDD | DSI_PWCTLR2_AVCL)
+#define DSI_SPD1_T2D BIT(3)
+#define DSI_CMD2_BK1_SPD1_SET (GENMASK(6, 4) | DSI_SPD1_T2D)
+#define DSI_CMD2_BK1_SPD2_SET DSI_CMD2_BK1_SPD1_SET
+#define DSI_MIPISET1_EOT_EN BIT(3)
+#define DSI_CMD2_BK1_MIPISET1_SET (BIT(7) | DSI_MIPISET1_EOT_EN)
+
+struct st7701_panel_desc {
+ const struct drm_display_mode *mode;
+ unsigned int lanes;
+ unsigned long flags;
+ enum mipi_dsi_pixel_format format;
+ const char *const *supply_names;
+ unsigned int num_supplies;
+ unsigned int panel_sleep_delay;
+};
+
+struct st7701 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ const struct st7701_panel_desc *desc;
+
+ struct backlight_device *backlight;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset;
+ unsigned int sleep_delay;
+};
+
+static inline struct st7701 *panel_to_st7701(struct drm_panel *panel)
+{
+ return container_of(panel, struct st7701, panel);
+}
+
+static inline int st7701_dsi_write(struct st7701 *st7701, const void *seq,
+ size_t len)
+{
+ return mipi_dsi_dcs_write_buffer(st7701->dsi, seq, len);
+}
+
+#define ST7701_DSI(st7701, seq...) \
+ { \
+ const u8 d[] = { seq }; \
+ st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \
+ }
+
+static void st7701_init_sequence(struct st7701 *st7701)
+{
+ const struct drm_display_mode *mode = st7701->desc->mode;
+
+ ST7701_DSI(st7701, MIPI_DCS_SOFT_RESET, 0x00);
+
+ /* We need to wait 5ms before sending new commands */
+ msleep(5);
+
+ ST7701_DSI(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);
+
+ msleep(st7701->sleep_delay);
+
+ /* Command2, BK0 */
+ ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
+ 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK0_SEL);
+ ST7701_DSI(st7701, DSI_CMD2_BK0_PVGAMCTRL, 0x00, 0x0E, 0x15, 0x0F,
+ 0x11, 0x08, 0x08, 0x08, 0x08, 0x23, 0x04, 0x13, 0x12,
+ 0x2B, 0x34, 0x1F);
+ ST7701_DSI(st7701, DSI_CMD2_BK0_NVGAMCTRL, 0x00, 0x0E, 0x95, 0x0F,
+ 0x13, 0x07, 0x09, 0x08, 0x08, 0x22, 0x04, 0x10, 0x0E,
+ 0x2C, 0x34, 0x1F);
+ ST7701_DSI(st7701, DSI_CMD2_BK0_LNESET,
+ DSI_CMD2_BK0_LNESET_B0, DSI_CMD2_BK0_LNESET_B1);
+ ST7701_DSI(st7701, DSI_CMD2_BK0_PORCTRL,
+ DSI_CMD2_BK0_PORCTRL_B0(mode),
+ DSI_CMD2_BK0_PORCTRL_B1(mode));
+ ST7701_DSI(st7701, DSI_CMD2_BK0_INVSEL,
+ DSI_CMD2_BK0_INVSEL_B0, DSI_CMD2_BK0_INVSEL_B1);
+
+ /* Command2, BK1 */
+ ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
+ 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS, DSI_CMD2_BK1_VRHA_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_VCOM, DSI_CMD2_BK1_VCOM_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_VGHSS, DSI_CMD2_BK1_VGHSS_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_TESTCMD, DSI_CMD2_BK1_TESTCMD_VAL);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_VGLS, DSI_CMD2_BK1_VGLS_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR1, DSI_CMD2_BK1_PWCTLR1_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR2, DSI_CMD2_BK1_PWCTLR2_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, DSI_CMD2_BK1_SPD1_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_SPD2, DSI_CMD2_BK1_SPD2_SET);
+ ST7701_DSI(st7701, DSI_CMD2_BK1_MIPISET1, DSI_CMD2_BK1_MIPISET1_SET);
+
+ /**
+ * ST7701_SPEC_V1.2 is unable to provide enough information above this
+ * specific command sequence, so grab the same from vendor BSP driver.
+ */
+ ST7701_DSI(st7701, 0xE0, 0x00, 0x00, 0x02);
+ ST7701_DSI(st7701, 0xE1, 0x0B, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0E,
+ 0x00, 0x00, 0x44, 0x44);
+ ST7701_DSI(st7701, 0xE2, 0x33, 0x33, 0x44, 0x44, 0x64, 0x00, 0x66,
+ 0x00, 0x65, 0x00, 0x67, 0x00, 0x00);
+ ST7701_DSI(st7701, 0xE3, 0x00, 0x00, 0x33, 0x33);
+ ST7701_DSI(st7701, 0xE4, 0x44, 0x44);
+ ST7701_DSI(st7701, 0xE5, 0x0C, 0x78, 0x3C, 0xA0, 0x0E, 0x78, 0x3C,
+ 0xA0, 0x10, 0x78, 0x3C, 0xA0, 0x12, 0x78, 0x3C, 0xA0);
+ ST7701_DSI(st7701, 0xE6, 0x00, 0x00, 0x33, 0x33);
+ ST7701_DSI(st7701, 0xE7, 0x44, 0x44);
+ ST7701_DSI(st7701, 0xE8, 0x0D, 0x78, 0x3C, 0xA0, 0x0F, 0x78, 0x3C,
+ 0xA0, 0x11, 0x78, 0x3C, 0xA0, 0x13, 0x78, 0x3C, 0xA0);
+ ST7701_DSI(st7701, 0xEB, 0x02, 0x02, 0x39, 0x39, 0xEE, 0x44, 0x00);
+ ST7701_DSI(st7701, 0xEC, 0x00, 0x00);
+ ST7701_DSI(st7701, 0xED, 0xFF, 0xF1, 0x04, 0x56, 0x72, 0x3F, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xF3, 0x27, 0x65, 0x40, 0x1F, 0xFF);
+
+ /* disable Command2 */
+ ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
+ 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
+}
+
+static int st7701_prepare(struct drm_panel *panel)
+{
+ struct st7701 *st7701 = panel_to_st7701(panel);
+ int ret;
+
+ gpiod_set_value(st7701->reset, 0);
+
+ ret = regulator_bulk_enable(st7701->desc->num_supplies,
+ st7701->supplies);
+ if (ret < 0)
+ return ret;
+ msleep(20);
+
+ gpiod_set_value(st7701->reset, 1);
+ msleep(150);
+
+ st7701_init_sequence(st7701);
+
+ return 0;
+}
+
+static int st7701_enable(struct drm_panel *panel)
+{
+ struct st7701 *st7701 = panel_to_st7701(panel);
+
+ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
+ backlight_enable(st7701->backlight);
+
+ return 0;
+}
+
+static int st7701_disable(struct drm_panel *panel)
+{
+ struct st7701 *st7701 = panel_to_st7701(panel);
+
+ backlight_disable(st7701->backlight);
+ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
+
+ return 0;
+}
+
+static int st7701_unprepare(struct drm_panel *panel)
+{
+ struct st7701 *st7701 = panel_to_st7701(panel);
+
+ ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
+
+ msleep(st7701->sleep_delay);
+
+ gpiod_set_value(st7701->reset, 0);
+
+ /**
+ * During the Resetting period, the display will be blanked
+ * (The display is entering blanking sequence, which maximum
+ * time is 120 ms, when Reset Starts in Sleep Out –mode. The
+ * display remains the blank state in Sleep In –mode.) and
+ * then return to Default condition for Hardware Reset.
+ *
+ * So we need wait sleep_delay time to make sure reset completed.
+ */
+ msleep(st7701->sleep_delay);
+
+ regulator_bulk_disable(st7701->desc->num_supplies, st7701->supplies);
+
+ return 0;
+}
+
+static int st7701_get_modes(struct drm_panel *panel)
+{
+ struct st7701 *st7701 = panel_to_st7701(panel);
+ const struct drm_display_mode *desc_mode = st7701->desc->mode;
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, desc_mode);
+ if (!mode) {
+ DRM_DEV_ERROR(&st7701->dsi->dev,
+ "failed to add mode %ux%ux@%u\n",
+ desc_mode->hdisplay, desc_mode->vdisplay,
+ desc_mode->vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(panel->connector, mode);
+
+ panel->connector->display_info.width_mm = desc_mode->width_mm;
+ panel->connector->display_info.height_mm = desc_mode->height_mm;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs st7701_funcs = {
+ .disable = st7701_disable,
+ .unprepare = st7701_unprepare,
+ .prepare = st7701_prepare,
+ .enable = st7701_enable,
+ .get_modes = st7701_get_modes,
+};
+
+static const struct drm_display_mode ts8550b_mode = {
+ .clock = 27500,
+
+ .hdisplay = 480,
+ .hsync_start = 480 + 38,
+ .hsync_end = 480 + 38 + 12,
+ .htotal = 480 + 38 + 12 + 12,
+
+ .vdisplay = 854,
+ .vsync_start = 854 + 4,
+ .vsync_end = 854 + 4 + 8,
+ .vtotal = 854 + 4 + 8 + 18,
+
+ .width_mm = 69,
+ .height_mm = 139,
+
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const char * const ts8550b_supply_names[] = {
+ "VCC",
+ "IOVCC",
+};
+
+static const struct st7701_panel_desc ts8550b_desc = {
+ .mode = &ts8550b_mode,
+ .lanes = 2,
+ .flags = MIPI_DSI_MODE_VIDEO,
+ .format = MIPI_DSI_FMT_RGB888,
+ .supply_names = ts8550b_supply_names,
+ .num_supplies = ARRAY_SIZE(ts8550b_supply_names),
+ .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */
+};
+
+static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ const struct st7701_panel_desc *desc;
+ struct st7701 *st7701;
+ int ret, i;
+
+ st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL);
+ if (!st7701)
+ return -ENOMEM;
+
+ desc = of_device_get_match_data(&dsi->dev);
+ dsi->mode_flags = desc->flags;
+ dsi->format = desc->format;
+ dsi->lanes = desc->lanes;
+
+ st7701->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies,
+ sizeof(*st7701->supplies),
+ GFP_KERNEL);
+ if (!st7701->supplies)
+ return -ENOMEM;
+
+ for (i = 0; i < desc->num_supplies; i++)
+ st7701->supplies[i].supply = desc->supply_names[i];
+
+ ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies,
+ st7701->supplies);
+ if (ret < 0)
+ return ret;
+
+ st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(st7701->reset)) {
+ DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+ return PTR_ERR(st7701->reset);
+ }
+
+ st7701->backlight = devm_of_find_backlight(&dsi->dev);
+ if (IS_ERR(st7701->backlight))
+ return PTR_ERR(st7701->backlight);
+
+ drm_panel_init(&st7701->panel);
+
+ /**
+ * Once sleep out has been issued, ST7701 IC required to wait 120ms
+ * before initiating new commands.
+ *
+ * On top of that some panels might need an extra delay to wait, so
+ * add panel specific delay for those cases. As now this panel specific
+ * delay information is referenced from those panel BSP driver, example
+ * ts8550b and there is no valid documentation for that.
+ */
+ st7701->sleep_delay = 120 + desc->panel_sleep_delay;
+ st7701->panel.funcs = &st7701_funcs;
+ st7701->panel.dev = &dsi->dev;
+
+ ret = drm_panel_add(&st7701->panel);
+ if (ret < 0)
+ return ret;
+
+ mipi_dsi_set_drvdata(dsi, st7701);
+ st7701->dsi = dsi;
+ st7701->desc = desc;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int st7701_dsi_remove(struct mipi_dsi_device *dsi)
+{
+ struct st7701 *st7701 = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&st7701->panel);
+
+ return 0;
+}
+
+static const struct of_device_id st7701_of_match[] = {
+ { .compatible = "techstar,ts8550b", .data = &ts8550b_desc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, st7701_of_match);
+
+static struct mipi_dsi_driver st7701_dsi_driver = {
+ .probe = st7701_dsi_probe,
+ .remove = st7701_dsi_remove,
+ .driver = {
+ .name = "st7701",
+ .of_match_table = st7701_of_match,
+ },
+};
+module_mipi_dsi_driver(st7701_dsi_driver);
+
+MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
+MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index 33e0483d62ae..a8958c201a88 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -64,14 +64,14 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_of.h>
-#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "pl111_drm.h"
#include "pl111_versatile.h"
diff --git a/drivers/gpu/drm/qxl/Makefile b/drivers/gpu/drm/qxl/Makefile
index 33a7d0c434b7..fc59d42b31af 100644
--- a/drivers/gpu/drm/qxl/Makefile
+++ b/drivers/gpu/drm/qxl/Makefile
@@ -2,6 +2,6 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_fb.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_release.o qxl_prime.o
+qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_release.o qxl_prime.o
obj-$(CONFIG_DRM_QXL)+= qxl.o
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 2e100f644236..0a2e51af1230 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -374,25 +374,25 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev)
void qxl_io_destroy_primary(struct qxl_device *qdev)
{
wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
- qdev->primary_created = false;
+ qdev->primary_bo->is_primary = false;
+ drm_gem_object_put_unlocked(&qdev->primary_bo->gem_base);
+ qdev->primary_bo = NULL;
}
-void qxl_io_create_primary(struct qxl_device *qdev,
- unsigned int offset, struct qxl_bo *bo)
+void qxl_io_create_primary(struct qxl_device *qdev, struct qxl_bo *bo)
{
struct qxl_surface_create *create;
+ if (WARN_ON(qdev->primary_bo))
+ return;
+
DRM_DEBUG_DRIVER("qdev %p, ram_header %p\n", qdev, qdev->ram_header);
create = &qdev->ram_header->create_surface;
create->format = bo->surf.format;
create->width = bo->surf.width;
create->height = bo->surf.height;
create->stride = bo->surf.stride;
- if (bo->shadow) {
- create->mem = qxl_bo_physical_address(qdev, bo->shadow, offset);
- } else {
- create->mem = qxl_bo_physical_address(qdev, bo, offset);
- }
+ create->mem = qxl_bo_physical_address(qdev, bo, 0);
DRM_DEBUG_DRIVER("mem = %llx, from %p\n", create->mem, bo->kptr);
@@ -400,7 +400,9 @@ void qxl_io_create_primary(struct qxl_device *qdev,
create->type = QXL_SURF_TYPE_PRIMARY;
wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC);
- qdev->primary_created = true;
+ qdev->primary_bo = bo;
+ qdev->primary_bo->is_primary = true;
+ drm_gem_object_get(&qdev->primary_bo->gem_base);
}
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id)
@@ -460,8 +462,7 @@ void qxl_surface_id_dealloc(struct qxl_device *qdev,
}
int qxl_hw_surface_alloc(struct qxl_device *qdev,
- struct qxl_bo *surf,
- struct ttm_mem_reg *new_mem)
+ struct qxl_bo *surf)
{
struct qxl_surface_cmd *cmd;
struct qxl_release *release;
@@ -487,16 +488,7 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
cmd->u.surface_create.width = surf->surf.width;
cmd->u.surface_create.height = surf->surf.height;
cmd->u.surface_create.stride = surf->surf.stride;
- if (new_mem) {
- int slot_id = surf->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot;
- struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]);
-
- /* TODO - need to hold one of the locks to read tbo.offset */
- cmd->u.surface_create.data = slot->high_bits;
-
- cmd->u.surface_create.data |= (new_mem->start << PAGE_SHIFT) + surf->tbo.bdev->man[new_mem->mem_type].gpu_offset;
- } else
- cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0);
+ cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0);
cmd->surface_id = surf->surface_id;
qxl_release_unmap(qdev, release, &cmd->release_info);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 1f8fddcc34d6..08c725544a2f 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -24,11 +24,11 @@
*/
#include <linux/crc32.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "qxl_drv.h"
#include "qxl_object.h"
@@ -80,10 +80,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
DRM_DEBUG_KMS("no client monitors configured\n");
return status;
}
- if (num_monitors > qdev->monitors_config->max_allowed) {
+ if (num_monitors > qxl_num_crtc) {
DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
- qdev->monitors_config->max_allowed, num_monitors);
- num_monitors = qdev->monitors_config->max_allowed;
+ qxl_num_crtc, num_monitors);
+ num_monitors = qxl_num_crtc;
} else {
num_monitors = qdev->rom->client_monitors_config.count;
}
@@ -96,8 +96,7 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
return status;
}
/* we copy max from the client but it isn't used */
- qdev->client_monitors_config->max_allowed =
- qdev->monitors_config->max_allowed;
+ qdev->client_monitors_config->max_allowed = qxl_num_crtc;
for (i = 0 ; i < qdev->client_monitors_config->count ; ++i) {
struct qxl_urect *c_rect =
&qdev->rom->client_monitors_config.heads[i];
@@ -191,20 +190,63 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
}
}
-static int qxl_add_monitors_config_modes(struct drm_connector *connector,
- unsigned *pwidth,
- unsigned *pheight)
+static int qxl_check_mode(struct qxl_device *qdev,
+ unsigned int width,
+ unsigned int height)
+{
+ unsigned int stride;
+ unsigned int size;
+
+ if (check_mul_overflow(width, 4u, &stride))
+ return -EINVAL;
+ if (check_mul_overflow(stride, height, &size))
+ return -EINVAL;
+ if (size > qdev->vram_size)
+ return -ENOMEM;
+ return 0;
+}
+
+static int qxl_check_framebuffer(struct qxl_device *qdev,
+ struct qxl_bo *bo)
+{
+ return qxl_check_mode(qdev, bo->surf.width, bo->surf.height);
+}
+
+static int qxl_add_mode(struct drm_connector *connector,
+ unsigned int width,
+ unsigned int height,
+ bool preferred)
+{
+ struct drm_device *dev = connector->dev;
+ struct qxl_device *qdev = dev->dev_private;
+ struct drm_display_mode *mode = NULL;
+ int rc;
+
+ rc = qxl_check_mode(qdev, width, height);
+ if (rc != 0)
+ return 0;
+
+ mode = drm_cvt_mode(dev, width, height, 60, false, false, false);
+ if (preferred)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ mode->hdisplay = width;
+ mode->vdisplay = height;
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ return 1;
+}
+
+static int qxl_add_monitors_config_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_output *output = drm_connector_to_qxl_output(connector);
int h = output->index;
- struct drm_display_mode *mode = NULL;
struct qxl_head *head;
if (!qdev->monitors_config)
return 0;
- if (h >= qdev->monitors_config->max_allowed)
+ if (h >= qxl_num_crtc)
return 0;
if (!qdev->client_monitors_config)
return 0;
@@ -214,60 +256,28 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector,
head = &qdev->client_monitors_config->heads[h];
DRM_DEBUG_KMS("head %d is %dx%d\n", h, head->width, head->height);
- mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,
- false);
- mode->type |= DRM_MODE_TYPE_PREFERRED;
- mode->hdisplay = head->width;
- mode->vdisplay = head->height;
- drm_mode_set_name(mode);
- *pwidth = head->width;
- *pheight = head->height;
- drm_mode_probed_add(connector, mode);
- /* remember the last custom size for mode validation */
- qdev->monitors_config_width = mode->hdisplay;
- qdev->monitors_config_height = mode->vdisplay;
- return 1;
+ return qxl_add_mode(connector, head->width, head->height, true);
}
static struct mode_size {
int w;
int h;
-} common_modes[] = {
- { 640, 480},
+} extra_modes[] = {
{ 720, 480},
- { 800, 600},
- { 848, 480},
- {1024, 768},
{1152, 768},
- {1280, 720},
- {1280, 800},
{1280, 854},
- {1280, 960},
- {1280, 1024},
- {1440, 900},
- {1400, 1050},
- {1680, 1050},
- {1600, 1200},
- {1920, 1080},
- {1920, 1200}
};
-static int qxl_add_common_modes(struct drm_connector *connector,
- unsigned int pwidth,
- unsigned int pheight)
+static int qxl_add_extra_modes(struct drm_connector *connector)
{
- struct drm_device *dev = connector->dev;
- struct drm_display_mode *mode = NULL;
- int i;
+ int i, ret = 0;
- for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
- mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,
- 60, false, false, false);
- if (common_modes[i].w == pwidth && common_modes[i].h == pheight)
- mode->type |= DRM_MODE_TYPE_PREFERRED;
- drm_mode_probed_add(connector, mode);
- }
- return i - 1;
+ for (i = 0; i < ARRAY_SIZE(extra_modes); i++)
+ ret += qxl_add_mode(connector,
+ extra_modes[i].w,
+ extra_modes[i].h,
+ false);
+ return ret;
}
static void qxl_send_monitors_config(struct qxl_device *qdev)
@@ -302,13 +312,12 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
struct qxl_head head;
int oldcount, i = qcrtc->index;
- if (!qdev->primary_created) {
+ if (!qdev->primary_bo) {
DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason);
return;
}
- if (!qdev->monitors_config ||
- qdev->monitors_config->max_allowed <= i)
+ if (!qdev->monitors_config || qxl_num_crtc <= i)
return;
head.id = i;
@@ -323,6 +332,8 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
head.y = crtc->y;
if (qdev->monitors_config->count < i + 1)
qdev->monitors_config->count = i + 1;
+ if (qdev->primary_bo == qdev->dumb_shadow_bo)
+ head.x += qdev->dumb_heads[i].x;
} else if (i > 0) {
head.width = 0;
head.height = 0;
@@ -348,9 +359,10 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
if (oldcount != qdev->monitors_config->count)
DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
oldcount, qdev->monitors_config->count,
- qdev->monitors_config->max_allowed);
+ qxl_num_crtc);
qdev->monitors_config->heads[i] = head;
+ qdev->monitors_config->max_allowed = qxl_num_crtc;
qxl_send_monitors_config(qdev);
}
@@ -401,13 +413,15 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct qxl_device *qdev = fb->dev->dev_private;
struct drm_clip_rect norect;
struct qxl_bo *qobj;
+ bool is_primary;
int inc = 1;
drm_modeset_lock_all(fb->dev);
qobj = gem_to_qxl_bo(fb->obj[0]);
/* if we aren't primary surface ignore this */
- if (!qobj->is_primary) {
+ is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary;
+ if (!is_primary) {
drm_modeset_unlock_all(fb->dev);
return 0;
}
@@ -424,7 +438,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
}
qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
- clips, num_clips, inc);
+ clips, num_clips, inc, 0);
drm_modeset_unlock_all(fb->dev);
@@ -466,12 +480,7 @@ static int qxl_primary_atomic_check(struct drm_plane *plane,
bo = gem_to_qxl_bo(state->fb->obj[0]);
- if (bo->surf.stride * bo->surf.height > qdev->vram_size) {
- DRM_ERROR("Mode doesn't fit in vram size (vgamem)");
- return -EINVAL;
- }
-
- return 0;
+ return qxl_check_framebuffer(qdev, bo);
}
static int qxl_primary_apply_cursor(struct drm_plane *plane)
@@ -526,15 +535,14 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_bo *bo = gem_to_qxl_bo(plane->state->fb->obj[0]);
- struct qxl_bo *bo_old;
+ struct qxl_bo *bo_old, *primary;
struct drm_clip_rect norect = {
.x1 = 0,
.y1 = 0,
.x2 = plane->state->fb->width,
.y2 = plane->state->fb->height
};
- int ret;
- bool same_shadow = false;
+ uint32_t dumb_shadow_offset = 0;
if (old_state->fb) {
bo_old = gem_to_qxl_bo(old_state->fb->obj[0]);
@@ -542,32 +550,21 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
bo_old = NULL;
}
- if (bo == bo_old)
- return;
+ primary = bo->shadow ? bo->shadow : bo;
- if (bo_old && bo_old->shadow && bo->shadow &&
- bo_old->shadow == bo->shadow) {
- same_shadow = true;
- }
-
- if (bo_old && bo_old->is_primary) {
- if (!same_shadow)
+ if (!primary->is_primary) {
+ if (qdev->primary_bo)
qxl_io_destroy_primary(qdev);
- bo_old->is_primary = false;
-
- ret = qxl_primary_apply_cursor(plane);
- if (ret)
- DRM_ERROR(
- "could not set cursor after creating primary");
+ qxl_io_create_primary(qdev, primary);
+ qxl_primary_apply_cursor(plane);
}
- if (!bo->is_primary) {
- if (!same_shadow)
- qxl_io_create_primary(qdev, 0, bo);
- bo->is_primary = true;
- }
+ if (bo->is_dumb)
+ dumb_shadow_offset =
+ qdev->dumb_heads[plane->state->crtc->index].x;
- qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1);
+ qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1,
+ dumb_shadow_offset);
}
static void qxl_primary_atomic_disable(struct drm_plane *plane,
@@ -723,12 +720,68 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane,
qxl_release_fence_buffer_objects(release);
}
+static void qxl_update_dumb_head(struct qxl_device *qdev,
+ int index, struct qxl_bo *bo)
+{
+ uint32_t width, height;
+
+ if (index >= qdev->monitors_config->max_allowed)
+ return;
+
+ if (bo && bo->is_dumb) {
+ width = bo->surf.width;
+ height = bo->surf.height;
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ if (qdev->dumb_heads[index].width == width &&
+ qdev->dumb_heads[index].height == height)
+ return;
+
+ DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index,
+ qdev->dumb_heads[index].width,
+ qdev->dumb_heads[index].height,
+ width, height);
+ qdev->dumb_heads[index].width = width;
+ qdev->dumb_heads[index].height = height;
+}
+
+static void qxl_calc_dumb_shadow(struct qxl_device *qdev,
+ struct qxl_surface *surf)
+{
+ struct qxl_head *head;
+ int i;
+
+ memset(surf, 0, sizeof(*surf));
+ for (i = 0; i < qdev->monitors_config->max_allowed; i++) {
+ head = qdev->dumb_heads + i;
+ head->x = surf->width;
+ surf->width += head->width;
+ if (surf->height < head->height)
+ surf->height = head->height;
+ }
+ if (surf->width < 64)
+ surf->width = 64;
+ if (surf->height < 64)
+ surf->height = 64;
+ surf->format = SPICE_SURFACE_FMT_32_xRGB;
+ surf->stride = surf->width * 4;
+
+ if (!qdev->dumb_shadow_bo ||
+ qdev->dumb_shadow_bo->surf.width != surf->width ||
+ qdev->dumb_shadow_bo->surf.height != surf->height)
+ DRM_DEBUG("%dx%d\n", surf->width, surf->height);
+}
+
static int qxl_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct drm_gem_object *obj;
- struct qxl_bo *user_bo, *old_bo = NULL;
+ struct qxl_bo *user_bo;
+ struct qxl_surface surf;
int ret;
if (!new_state->fb)
@@ -738,28 +791,30 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane,
user_bo = gem_to_qxl_bo(obj);
if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
- user_bo->is_dumb && !user_bo->shadow) {
- if (plane->state->fb) {
- obj = plane->state->fb->obj[0];
- old_bo = gem_to_qxl_bo(obj);
+ user_bo->is_dumb) {
+ qxl_update_dumb_head(qdev, new_state->crtc->index,
+ user_bo);
+ qxl_calc_dumb_shadow(qdev, &surf);
+ if (!qdev->dumb_shadow_bo ||
+ qdev->dumb_shadow_bo->surf.width != surf.width ||
+ qdev->dumb_shadow_bo->surf.height != surf.height) {
+ if (qdev->dumb_shadow_bo) {
+ drm_gem_object_put_unlocked
+ (&qdev->dumb_shadow_bo->gem_base);
+ qdev->dumb_shadow_bo = NULL;
+ }
+ qxl_bo_create(qdev, surf.height * surf.stride,
+ true, true, QXL_GEM_DOMAIN_SURFACE, &surf,
+ &qdev->dumb_shadow_bo);
}
- if (old_bo && old_bo->shadow &&
- user_bo->gem_base.size == old_bo->gem_base.size &&
- plane->state->crtc == new_state->crtc &&
- plane->state->crtc_w == new_state->crtc_w &&
- plane->state->crtc_h == new_state->crtc_h &&
- plane->state->src_x == new_state->src_x &&
- plane->state->src_y == new_state->src_y &&
- plane->state->src_w == new_state->src_w &&
- plane->state->src_h == new_state->src_h &&
- plane->state->rotation == new_state->rotation &&
- plane->state->zpos == new_state->zpos) {
- drm_gem_object_get(&old_bo->shadow->gem_base);
- user_bo->shadow = old_bo->shadow;
- } else {
- qxl_bo_create(qdev, user_bo->gem_base.size,
- true, true, QXL_GEM_DOMAIN_VRAM, NULL,
- &user_bo->shadow);
+ if (user_bo->shadow != qdev->dumb_shadow_bo) {
+ if (user_bo->shadow) {
+ drm_gem_object_put_unlocked
+ (&user_bo->shadow->gem_base);
+ user_bo->shadow = NULL;
+ }
+ drm_gem_object_get(&qdev->dumb_shadow_bo->gem_base);
+ user_bo->shadow = qdev->dumb_shadow_bo;
}
}
@@ -788,7 +843,7 @@ static void qxl_plane_cleanup_fb(struct drm_plane *plane,
user_bo = gem_to_qxl_bo(obj);
qxl_bo_unpin(user_bo);
- if (user_bo->shadow && !user_bo->is_primary) {
+ if (old_state->fb != plane->state->fb && user_bo->shadow) {
drm_gem_object_put_unlocked(&user_bo->shadow->gem_base);
user_bo->shadow = NULL;
}
@@ -925,14 +980,26 @@ free_mem:
static int qxl_conn_get_modes(struct drm_connector *connector)
{
+ struct drm_device *dev = connector->dev;
+ struct qxl_device *qdev = dev->dev_private;
+ struct qxl_output *output = drm_connector_to_qxl_output(connector);
unsigned int pwidth = 1024;
unsigned int pheight = 768;
int ret = 0;
- ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
- if (ret < 0)
- return ret;
- ret += qxl_add_common_modes(connector, pwidth, pheight);
+ if (qdev->client_monitors_config) {
+ struct qxl_head *head;
+ head = &qdev->client_monitors_config->heads[output->index];
+ if (head->width)
+ pwidth = head->width;
+ if (head->height)
+ pheight = head->height;
+ }
+
+ ret += drm_add_modes_noedid(connector, 8192, 8192);
+ ret += qxl_add_extra_modes(connector);
+ ret += qxl_add_monitors_config_modes(connector);
+ drm_set_preferred_mode(connector, pwidth, pheight);
return ret;
}
@@ -941,20 +1008,11 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
{
struct drm_device *ddev = connector->dev;
struct qxl_device *qdev = ddev->dev_private;
- int i;
-
- /* TODO: is this called for user defined modes? (xrandr --add-mode)
- * TODO: check that the mode fits in the framebuffer */
- if (qdev->monitors_config_width == mode->hdisplay &&
- qdev->monitors_config_height == mode->vdisplay)
- return MODE_OK;
+ if (qxl_check_mode(qdev, mode->hdisplay, mode->vdisplay) != 0)
+ return MODE_BAD;
- for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
- if (common_modes[i].w == mode->hdisplay && common_modes[i].h == mode->vdisplay)
- return MODE_OK;
- }
- return MODE_BAD;
+ return MODE_OK;
}
static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
@@ -1096,9 +1154,8 @@ int qxl_create_monitors_object(struct qxl_device *qdev)
{
int ret;
struct drm_gem_object *gobj;
- int max_allowed = qxl_num_crtc;
int monitors_config_size = sizeof(struct qxl_monitors_config) +
- max_allowed * sizeof(struct qxl_head);
+ qxl_num_crtc * sizeof(struct qxl_head);
ret = qxl_gem_object_create(qdev, monitors_config_size, 0,
QXL_GEM_DOMAIN_VRAM,
@@ -1120,7 +1177,12 @@ int qxl_create_monitors_object(struct qxl_device *qdev)
qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0);
memset(qdev->monitors_config, 0, monitors_config_size);
- qdev->monitors_config->max_allowed = max_allowed;
+ qdev->dumb_heads = kcalloc(qxl_num_crtc, sizeof(qdev->dumb_heads[0]),
+ GFP_KERNEL);
+ if (!qdev->dumb_heads) {
+ qxl_destroy_monitors_object(qdev);
+ return -ENOMEM;
+ }
return 0;
}
@@ -1172,18 +1234,11 @@ int qxl_modeset_init(struct qxl_device *qdev)
qxl_display_read_client_monitors_config(qdev);
drm_mode_config_reset(&qdev->ddev);
-
- /* primary surface must be created by this point, to allow
- * issuing command queue commands and having them read by
- * spice server. */
- qxl_fbdev_init(qdev);
return 0;
}
void qxl_modeset_fini(struct qxl_device *qdev)
{
- qxl_fbdev_fini(qdev);
-
qxl_destroy_monitors_object(qdev);
drm_mode_config_cleanup(&qdev->ddev);
}
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index c408bb83c7a9..97c3f1a95a32 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -109,152 +109,6 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
return 0;
}
-static int alloc_palette_object(struct qxl_device *qdev,
- struct qxl_release *release,
- struct qxl_bo **palette_bo)
-{
- return qxl_alloc_bo_reserved(qdev, release,
- sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
- palette_bo);
-}
-
-static int qxl_palette_create_1bit(struct qxl_bo *palette_bo,
- struct qxl_release *release,
- const struct qxl_fb_image *qxl_fb_image)
-{
- const struct fb_image *fb_image = &qxl_fb_image->fb_image;
- uint32_t visual = qxl_fb_image->visual;
- const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette;
- struct qxl_palette *pal;
- int ret;
- uint32_t fgcolor, bgcolor;
- static uint64_t unique; /* we make no attempt to actually set this
- * correctly globaly, since that would require
- * tracking all of our palettes. */
- ret = qxl_bo_kmap(palette_bo, (void **)&pal);
- if (ret)
- return ret;
- pal->num_ents = 2;
- pal->unique = unique++;
- if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
- /* NB: this is the only used branch currently. */
- fgcolor = pseudo_palette[fb_image->fg_color];
- bgcolor = pseudo_palette[fb_image->bg_color];
- } else {
- fgcolor = fb_image->fg_color;
- bgcolor = fb_image->bg_color;
- }
- pal->ents[0] = bgcolor;
- pal->ents[1] = fgcolor;
- qxl_bo_kunmap(palette_bo);
- return 0;
-}
-
-void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
- int stride /* filled in if 0 */)
-{
- struct qxl_device *qdev = qxl_fb_image->qdev;
- struct qxl_drawable *drawable;
- struct qxl_rect rect;
- const struct fb_image *fb_image = &qxl_fb_image->fb_image;
- int x = fb_image->dx;
- int y = fb_image->dy;
- int width = fb_image->width;
- int height = fb_image->height;
- const char *src = fb_image->data;
- int depth = fb_image->depth;
- struct qxl_release *release;
- struct qxl_image *image;
- int ret;
- struct qxl_drm_image *dimage;
- struct qxl_bo *palette_bo = NULL;
-
- if (stride == 0)
- stride = depth * width / 8;
-
- ret = alloc_drawable(qdev, &release);
- if (ret)
- return;
-
- ret = qxl_image_alloc_objects(qdev, release,
- &dimage,
- height, stride);
- if (ret)
- goto out_free_drawable;
-
- if (depth == 1) {
- ret = alloc_palette_object(qdev, release, &palette_bo);
- if (ret)
- goto out_free_image;
- }
-
- /* do a reservation run over all the objects we just allocated */
- ret = qxl_release_reserve_list(release, true);
- if (ret)
- goto out_free_palette;
-
- rect.left = x;
- rect.right = x + width;
- rect.top = y;
- rect.bottom = y + height;
-
- ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release);
- if (ret) {
- qxl_release_backoff_reserve_list(release);
- goto out_free_palette;
- }
-
- ret = qxl_image_init(qdev, release, dimage,
- (const uint8_t *)src, 0, 0,
- width, height, depth, stride);
- if (ret) {
- qxl_release_backoff_reserve_list(release);
- qxl_release_free(qdev, release);
- return;
- }
-
- if (depth == 1) {
- void *ptr;
-
- ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
-
- ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
- image = ptr;
- image->u.bitmap.palette =
- qxl_bo_physical_address(qdev, palette_bo, 0);
- qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr);
- }
-
- drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
-
- drawable->u.copy.src_area.top = 0;
- drawable->u.copy.src_area.bottom = height;
- drawable->u.copy.src_area.left = 0;
- drawable->u.copy.src_area.right = width;
-
- drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
- drawable->u.copy.scale_mode = 0;
- drawable->u.copy.mask.flags = 0;
- drawable->u.copy.mask.pos.x = 0;
- drawable->u.copy.mask.pos.y = 0;
- drawable->u.copy.mask.bitmap = 0;
-
- drawable->u.copy.src_bitmap =
- qxl_bo_physical_address(qdev, dimage->bo, 0);
- qxl_release_unmap(qdev, release, &drawable->release_info);
-
- qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_fence_buffer_objects(release);
-
-out_free_palette:
- qxl_bo_unref(&palette_bo);
-out_free_image:
- qxl_image_free_objects(qdev, dimage);
-out_free_drawable:
- if (ret)
- free_drawable(qdev, release);
-}
-
/* push a draw command using the given clipping rectangles as
* the sources from the shadow framebuffer.
*
@@ -267,7 +121,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
struct qxl_bo *bo,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned int num_clips, int inc)
+ unsigned int num_clips, int inc,
+ uint32_t dumb_shadow_offset)
{
/*
* TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
@@ -295,6 +150,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
if (ret)
return;
+ clips->x1 += dumb_shadow_offset;
+ clips->x2 += dumb_shadow_offset;
+
left = clips->x1;
right = clips->x2;
top = clips->y1;
@@ -342,7 +200,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
goto out_release_backoff;
ret = qxl_image_init(qdev, release, dimage, surface_base,
- left, top, width, height, depth, stride);
+ left - dumb_shadow_offset,
+ top, width, height, depth, stride);
qxl_bo_kunmap(bo);
if (ret)
goto out_release_backoff;
@@ -397,89 +256,3 @@ out_free_drawable:
free_drawable(qdev, release);
}
-
-void qxl_draw_copyarea(struct qxl_device *qdev,
- u32 width, u32 height,
- u32 sx, u32 sy,
- u32 dx, u32 dy)
-{
- struct qxl_drawable *drawable;
- struct qxl_rect rect;
- struct qxl_release *release;
- int ret;
-
- ret = alloc_drawable(qdev, &release);
- if (ret)
- return;
-
- /* do a reservation run over all the objects we just allocated */
- ret = qxl_release_reserve_list(release, true);
- if (ret)
- goto out_free_release;
-
- rect.left = dx;
- rect.top = dy;
- rect.right = dx + width;
- rect.bottom = dy + height;
- ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release);
- if (ret) {
- qxl_release_backoff_reserve_list(release);
- goto out_free_release;
- }
-
- drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
- drawable->u.copy_bits.src_pos.x = sx;
- drawable->u.copy_bits.src_pos.y = sy;
- qxl_release_unmap(qdev, release, &drawable->release_info);
-
- qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_fence_buffer_objects(release);
-
-out_free_release:
- if (ret)
- free_drawable(qdev, release);
-}
-
-void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
-{
- struct qxl_device *qdev = qxl_draw_fill_rec->qdev;
- struct qxl_rect rect = qxl_draw_fill_rec->rect;
- uint32_t color = qxl_draw_fill_rec->color;
- uint16_t rop = qxl_draw_fill_rec->rop;
- struct qxl_drawable *drawable;
- struct qxl_release *release;
- int ret;
-
- ret = alloc_drawable(qdev, &release);
- if (ret)
- return;
-
- /* do a reservation run over all the objects we just allocated */
- ret = qxl_release_reserve_list(release, true);
- if (ret)
- goto out_free_release;
-
- ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release);
- if (ret) {
- qxl_release_backoff_reserve_list(release);
- goto out_free_release;
- }
-
- drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
- drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
- drawable->u.fill.brush.u.color = color;
- drawable->u.fill.rop_descriptor = rop;
- drawable->u.fill.mask.flags = 0;
- drawable->u.fill.mask.pos.x = 0;
- drawable->u.fill.mask.pos.y = 0;
- drawable->u.fill.mask.bitmap = 0;
-
- qxl_release_unmap(qdev, release, &drawable->release_info);
-
- qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_fence_buffer_objects(release);
-
-out_free_release:
- if (ret)
- free_drawable(qdev, release);
-}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 13c8a662f9b4..bb81e310eb6d 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -33,7 +33,8 @@
#include <drm/drmP.h>
#include <drm/drm.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_probe_helper.h>
#include "qxl_drv.h"
#include "qxl_object.h"
@@ -93,6 +94,8 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto modeset_cleanup;
+ drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "qxl");
+ drm_fbdev_generic_setup(&qdev->ddev, 32);
return 0;
modeset_cleanup:
@@ -242,7 +245,6 @@ static struct pci_driver qxl_pci_driver = {
static struct drm_driver qxl_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
DRIVER_ATOMIC,
.dumb_create = qxl_mode_dumb_create,
@@ -250,14 +252,10 @@ static struct drm_driver qxl_driver = {
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = qxl_debugfs_init,
#endif
- .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
- .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = qxl_gem_prime_pin,
.gem_prime_unpin = qxl_gem_prime_unpin,
- .gem_prime_get_sg_table = qxl_gem_prime_get_sg_table,
- .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table,
.gem_prime_vmap = qxl_gem_prime_vmap,
.gem_prime_vunmap = qxl_gem_prime_vunmap,
.gem_prime_mmap = qxl_gem_prime_mmap,
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 13a0254b59a1..4a0331b3ff7d 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -84,6 +84,7 @@ struct qxl_bo {
struct ttm_bo_kmap_obj kmap;
unsigned int pin_count;
void *kptr;
+ unsigned int map_count;
int type;
/* Constant after initialization */
@@ -130,10 +131,13 @@ struct qxl_mman {
};
struct qxl_memslot {
+ int index;
+ const char *name;
uint8_t generation;
uint64_t start_phys_addr;
- uint64_t end_phys_addr;
+ uint64_t size;
uint64_t high_bits;
+ uint64_t gpu_offset;
};
enum {
@@ -216,8 +220,6 @@ struct qxl_device {
struct qxl_mman mman;
struct qxl_gem gem;
- struct drm_fb_helper fb_helper;
-
void *ram_physical;
struct qxl_ring *release_ring;
@@ -226,16 +228,12 @@ struct qxl_device {
struct qxl_ram_header *ram_header;
- unsigned int primary_created:1;
-
- struct qxl_memslot *mem_slots;
- uint8_t n_mem_slots;
+ struct qxl_bo *primary_bo;
+ struct qxl_bo *dumb_shadow_bo;
+ struct qxl_head *dumb_heads;
- uint8_t main_mem_slot;
- uint8_t surfaces_mem_slot;
- uint8_t slot_id_bits;
- uint8_t slot_gen_bits;
- uint64_t va_slot_mask;
+ struct qxl_memslot main_slot;
+ struct qxl_memslot surfaces_slot;
spinlock_t release_lock;
struct idr release_idr;
@@ -308,30 +306,20 @@ void qxl_ring_free(struct qxl_ring *ring);
void qxl_ring_init_hdr(struct qxl_ring *ring);
int qxl_check_idle(struct qxl_ring *ring);
-static inline void *
-qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical)
-{
- DRM_DEBUG_DRIVER("not implemented (%lu)\n", physical);
- return 0;
-}
-
static inline uint64_t
qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo,
unsigned long offset)
{
- int slot_id = bo->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot;
- struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]);
+ struct qxl_memslot *slot =
+ (bo->tbo.mem.mem_type == TTM_PL_VRAM)
+ ? &qdev->main_slot : &qdev->surfaces_slot;
+
+ WARN_ON_ONCE((bo->tbo.offset & slot->gpu_offset) != slot->gpu_offset);
/* TODO - need to hold one of the locks to read tbo.offset */
- return slot->high_bits | (bo->tbo.offset + offset);
+ return slot->high_bits | (bo->tbo.offset - slot->gpu_offset + offset);
}
-/* qxl_fb.c */
-#define QXLFB_CONN_LIMIT 1
-
-int qxl_fbdev_init(struct qxl_device *qdev);
-void qxl_fbdev_fini(struct qxl_device *qdev);
-
/* qxl_display.c */
void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
int qxl_create_monitors_object(struct qxl_device *qdev);
@@ -392,7 +380,6 @@ void qxl_update_screen(struct qxl_device *qxl);
/* qxl io operations (qxl_cmd.c) */
void qxl_io_create_primary(struct qxl_device *qdev,
- unsigned int offset,
struct qxl_bo *bo);
void qxl_io_destroy_primary(struct qxl_device *qdev);
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -437,22 +424,13 @@ int qxl_alloc_bo_reserved(struct qxl_device *qdev,
struct qxl_bo **_bo);
/* qxl drawing commands */
-void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
- int stride /* filled in if 0 */);
-
void qxl_draw_dirty_fb(struct qxl_device *qdev,
struct drm_framebuffer *fb,
struct qxl_bo *bo,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned int num_clips, int inc);
-
-void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec);
-
-void qxl_draw_copyarea(struct qxl_device *qdev,
- u32 width, u32 height,
- u32 sx, u32 sy,
- u32 dx, u32 dy);
+ unsigned int num_clips, int inc,
+ uint32_t dumb_shadow_offset);
void qxl_release_free(struct qxl_device *qdev,
struct qxl_release *release);
@@ -485,9 +463,6 @@ int qxl_gem_prime_mmap(struct drm_gem_object *obj,
int qxl_irq_init(struct qxl_device *qdev);
irqreturn_t qxl_irq_handler(int irq, void *arg);
-/* qxl_fb.c */
-bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
-
int qxl_debugfs_add_files(struct qxl_device *qdev,
struct drm_info_list *files,
unsigned int nfiles);
@@ -497,8 +472,7 @@ int qxl_surface_id_alloc(struct qxl_device *qdev,
void qxl_surface_id_dealloc(struct qxl_device *qdev,
uint32_t surface_id);
int qxl_hw_surface_alloc(struct qxl_device *qdev,
- struct qxl_bo *surf,
- struct ttm_mem_reg *mem);
+ struct qxl_bo *surf);
int qxl_hw_surface_dealloc(struct qxl_device *qdev,
struct qxl_bo *surf);
diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c
index e3765739c396..272d19b677d8 100644
--- a/drivers/gpu/drm/qxl/qxl_dumb.c
+++ b/drivers/gpu/drm/qxl/qxl_dumb.c
@@ -59,7 +59,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
surf.stride = pitch;
surf.format = format;
r = qxl_gem_object_create_with_handle(qdev, file_priv,
- QXL_GEM_DOMAIN_VRAM,
+ QXL_GEM_DOMAIN_SURFACE,
args->size, &surf, &qobj,
&handle);
if (r)
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
deleted file mode 100644
index a819d24225d2..000000000000
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright © 2013 Red Hat
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * David Airlie
- */
-#include <linux/module.h>
-
-#include <drm/drmP.h>
-#include <drm/drm.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_framebuffer_helper.h>
-
-#include "qxl_drv.h"
-
-#include "qxl_object.h"
-
-static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image,
- struct qxl_device *qdev, struct fb_info *info,
- const struct fb_image *image)
-{
- qxl_fb_image->qdev = qdev;
- if (info) {
- qxl_fb_image->visual = info->fix.visual;
- if (qxl_fb_image->visual == FB_VISUAL_TRUECOLOR ||
- qxl_fb_image->visual == FB_VISUAL_DIRECTCOLOR)
- memcpy(&qxl_fb_image->pseudo_palette,
- info->pseudo_palette,
- sizeof(qxl_fb_image->pseudo_palette));
- } else {
- /* fallback */
- if (image->depth == 1)
- qxl_fb_image->visual = FB_VISUAL_MONO10;
- else
- qxl_fb_image->visual = FB_VISUAL_DIRECTCOLOR;
- }
- if (image) {
- memcpy(&qxl_fb_image->fb_image, image,
- sizeof(qxl_fb_image->fb_image));
- }
-}
-
-static struct fb_ops qxlfb_ops = {
- .owner = THIS_MODULE,
- DRM_FB_HELPER_DEFAULT_OPS,
- .fb_fillrect = drm_fb_helper_sys_fillrect,
- .fb_copyarea = drm_fb_helper_sys_copyarea,
- .fb_imageblit = drm_fb_helper_sys_imageblit,
-};
-
-static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj)
-{
- struct qxl_bo *qbo = gem_to_qxl_bo(gobj);
-
- qxl_bo_kunmap(qbo);
- qxl_bo_unpin(qbo);
-
- drm_gem_object_put_unlocked(gobj);
-}
-
-static int qxlfb_create_pinned_object(struct qxl_device *qdev,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object **gobj_p)
-{
- struct drm_gem_object *gobj = NULL;
- struct qxl_bo *qbo = NULL;
- int ret;
- int aligned_size, size;
- int height = mode_cmd->height;
-
- size = mode_cmd->pitches[0] * height;
- aligned_size = ALIGN(size, PAGE_SIZE);
- /* TODO: unallocate and reallocate surface0 for real. Hack to just
- * have a large enough surface0 for 1024x768 Xorg 32bpp mode */
- ret = qxl_gem_object_create(qdev, aligned_size, 0,
- QXL_GEM_DOMAIN_SURFACE,
- false, /* is discardable */
- false, /* is kernel (false means device) */
- NULL,
- &gobj);
- if (ret) {
- pr_err("failed to allocate framebuffer (%d)\n",
- aligned_size);
- return -ENOMEM;
- }
- qbo = gem_to_qxl_bo(gobj);
-
- qbo->surf.width = mode_cmd->width;
- qbo->surf.height = mode_cmd->height;
- qbo->surf.stride = mode_cmd->pitches[0];
- qbo->surf.format = SPICE_SURFACE_FMT_32_xRGB;
-
- ret = qxl_bo_pin(qbo);
- if (ret) {
- goto out_unref;
- }
- ret = qxl_bo_kmap(qbo, NULL);
-
- if (ret)
- goto out_unref;
-
- *gobj_p = gobj;
- return 0;
-out_unref:
- qxlfb_destroy_pinned_object(gobj);
- *gobj_p = NULL;
- return ret;
-}
-
-/*
- * FIXME
- * It should not be necessary to have a special dirty() callback for fbdev.
- */
-static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
- struct drm_file *file_priv,
- unsigned int flags, unsigned int color,
- struct drm_clip_rect *clips,
- unsigned int num_clips)
-{
- struct qxl_device *qdev = fb->dev->dev_private;
- struct fb_info *info = qdev->fb_helper.fbdev;
- struct qxl_fb_image qxl_fb_image;
- struct fb_image *image = &qxl_fb_image.fb_image;
-
- /* TODO: hard coding 32 bpp */
- int stride = fb->pitches[0];
-
- /*
- * we are using a shadow draw buffer, at qdev->surface0_shadow
- */
- image->dx = clips->x1;
- image->dy = clips->y1;
- image->width = clips->x2 - clips->x1;
- image->height = clips->y2 - clips->y1;
- image->fg_color = 0xffffffff; /* unused, just to avoid uninitialized
- warnings */
- image->bg_color = 0;
- image->depth = 32; /* TODO: take from somewhere? */
- image->cmap.start = 0;
- image->cmap.len = 0;
- image->cmap.red = NULL;
- image->cmap.green = NULL;
- image->cmap.blue = NULL;
- image->cmap.transp = NULL;
- image->data = info->screen_base + (clips->x1 * 4) + (stride * clips->y1);
-
- qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL);
- qxl_draw_opaque_fb(&qxl_fb_image, stride);
-
- return 0;
-}
-
-static const struct drm_framebuffer_funcs qxlfb_fb_funcs = {
- .destroy = drm_gem_fb_destroy,
- .create_handle = drm_gem_fb_create_handle,
- .dirty = qxlfb_framebuffer_dirty,
-};
-
-static int qxlfb_create(struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct qxl_device *qdev =
- container_of(helper, struct qxl_device, fb_helper);
- struct fb_info *info;
- struct drm_framebuffer *fb = NULL;
- struct drm_mode_fb_cmd2 mode_cmd;
- struct drm_gem_object *gobj = NULL;
- struct qxl_bo *qbo = NULL;
- int ret;
- int bpp = sizes->surface_bpp;
- int depth = sizes->surface_depth;
- void *shadow;
-
- mode_cmd.width = sizes->surface_width;
- mode_cmd.height = sizes->surface_height;
-
- mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64);
- mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
-
- ret = qxlfb_create_pinned_object(qdev, &mode_cmd, &gobj);
- if (ret < 0)
- return ret;
-
- qbo = gem_to_qxl_bo(gobj);
- DRM_DEBUG_DRIVER("%dx%d %d\n", mode_cmd.width,
- mode_cmd.height, mode_cmd.pitches[0]);
-
- shadow = vmalloc(array_size(mode_cmd.pitches[0], mode_cmd.height));
- /* TODO: what's the usual response to memory allocation errors? */
- BUG_ON(!shadow);
- DRM_DEBUG_DRIVER("surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n",
- qxl_bo_gpu_offset(qbo), qxl_bo_mmap_offset(qbo),
- qbo->kptr, shadow);
-
- info = drm_fb_helper_alloc_fbi(helper);
- if (IS_ERR(info)) {
- ret = PTR_ERR(info);
- goto out_unref;
- }
-
- info->par = helper;
-
- fb = drm_gem_fbdev_fb_create(&qdev->ddev, sizes, 64, gobj,
- &qxlfb_fb_funcs);
- if (IS_ERR(fb)) {
- DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb));
- ret = PTR_ERR(fb);
- goto out_unref;
- }
-
- /* setup helper with fb data */
- qdev->fb_helper.fb = fb;
-
- strcpy(info->fix.id, "qxldrmfb");
-
- drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
-
- info->fbops = &qxlfb_ops;
-
- /*
- * TODO: using gobj->size in various places in this function. Not sure
- * what the difference between the different sizes is.
- */
- info->fix.smem_start = qdev->vram_base; /* TODO - correct? */
- info->fix.smem_len = gobj->size;
- info->screen_base = shadow;
- info->screen_size = gobj->size;
-
- drm_fb_helper_fill_var(info, &qdev->fb_helper, sizes->fb_width,
- sizes->fb_height);
-
- /* setup aperture base/size for vesafb takeover */
- info->apertures->ranges[0].base = qdev->ddev.mode_config.fb_base;
- info->apertures->ranges[0].size = qdev->vram_size;
-
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
-
- if (info->screen_base == NULL) {
- ret = -ENOSPC;
- goto out_unref;
- }
-
- /* XXX error handling. */
- drm_fb_helper_defio_init(helper);
-
- DRM_INFO("fb mappable at 0x%lX, size %lu\n", info->fix.smem_start, (unsigned long)info->screen_size);
- DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n",
- fb->format->depth, fb->pitches[0], fb->width, fb->height);
- return 0;
-
-out_unref:
- if (qbo) {
- qxl_bo_kunmap(qbo);
- qxl_bo_unpin(qbo);
- }
- drm_gem_object_put_unlocked(gobj);
- return ret;
-}
-
-static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
- .fb_probe = qxlfb_create,
-};
-
-int qxl_fbdev_init(struct qxl_device *qdev)
-{
- return drm_fb_helper_fbdev_setup(&qdev->ddev, &qdev->fb_helper,
- &qxl_fb_helper_funcs, 32,
- QXLFB_CONN_LIMIT);
-}
-
-void qxl_fbdev_fini(struct qxl_device *qdev)
-{
- struct fb_info *fbi = qdev->fb_helper.fbdev;
- void *shadow = fbi ? fbi->screen_buffer : NULL;
-
- drm_fb_helper_fbdev_teardown(&qdev->ddev);
- vfree(shadow);
-}
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index 15238a413f9d..bee61fa2c9bc 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -26,7 +26,7 @@
#include "qxl_drv.h"
#include "qxl_object.h"
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/io-mapping.h>
int qxl_log_level;
@@ -53,40 +53,47 @@ static bool qxl_check_device(struct qxl_device *qdev)
return true;
}
-static void setup_hw_slot(struct qxl_device *qdev, int slot_index,
- struct qxl_memslot *slot)
+static void setup_hw_slot(struct qxl_device *qdev, struct qxl_memslot *slot)
{
qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr;
- qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr;
- qxl_io_memslot_add(qdev, slot_index);
+ qdev->ram_header->mem_slot.mem_end = slot->start_phys_addr + slot->size;
+ qxl_io_memslot_add(qdev, qdev->rom->slots_start + slot->index);
}
-static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
- unsigned long start_phys_addr, unsigned long end_phys_addr)
+static void setup_slot(struct qxl_device *qdev,
+ struct qxl_memslot *slot,
+ unsigned int slot_index,
+ const char *slot_name,
+ unsigned long start_phys_addr,
+ unsigned long size)
{
uint64_t high_bits;
- struct qxl_memslot *slot;
- uint8_t slot_index;
- slot_index = qdev->rom->slots_start + slot_index_offset;
- slot = &qdev->mem_slots[slot_index];
+ slot->index = slot_index;
+ slot->name = slot_name;
slot->start_phys_addr = start_phys_addr;
- slot->end_phys_addr = end_phys_addr;
+ slot->size = size;
- setup_hw_slot(qdev, slot_index, slot);
+ setup_hw_slot(qdev, slot);
slot->generation = qdev->rom->slot_generation;
- high_bits = slot_index << qdev->slot_gen_bits;
+ high_bits = (qdev->rom->slots_start + slot->index)
+ << qdev->rom->slot_gen_bits;
high_bits |= slot->generation;
- high_bits <<= (64 - (qdev->slot_gen_bits + qdev->slot_id_bits));
+ high_bits <<= (64 - (qdev->rom->slot_gen_bits + qdev->rom->slot_id_bits));
slot->high_bits = high_bits;
- return slot_index;
+
+ DRM_INFO("slot %d (%s): base 0x%08lx, size 0x%08lx, gpu_offset 0x%lx\n",
+ slot->index, slot->name,
+ (unsigned long)slot->start_phys_addr,
+ (unsigned long)slot->size,
+ (unsigned long)slot->gpu_offset);
}
void qxl_reinit_memslots(struct qxl_device *qdev)
{
- setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]);
- setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]);
+ setup_hw_slot(qdev, &qdev->main_slot);
+ setup_hw_slot(qdev, &qdev->surfaces_slot);
}
static void qxl_gc_work(struct work_struct *work)
@@ -229,23 +236,6 @@ int qxl_device_init(struct qxl_device *qdev,
r = -ENOMEM;
goto cursor_ring_free;
}
- /* TODO - slot initialization should happen on reset. where is our
- * reset handler? */
- qdev->n_mem_slots = qdev->rom->slots_end;
- qdev->slot_gen_bits = qdev->rom->slot_gen_bits;
- qdev->slot_id_bits = qdev->rom->slot_id_bits;
- qdev->va_slot_mask =
- (~(uint64_t)0) >> (qdev->slot_id_bits + qdev->slot_gen_bits);
-
- qdev->mem_slots =
- kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot),
- GFP_KERNEL);
-
- if (!qdev->mem_slots) {
- DRM_ERROR("Unable to alloc mem slots\n");
- r = -ENOMEM;
- goto release_ring_free;
- }
idr_init(&qdev->release_idr);
spin_lock_init(&qdev->release_idr_lock);
@@ -264,33 +254,24 @@ int qxl_device_init(struct qxl_device *qdev,
r = qxl_irq_init(qdev);
if (r) {
DRM_ERROR("Unable to init qxl irq\n");
- goto mem_slots_free;
+ goto release_ring_free;
}
/*
* Note that virtual is surface0. We rely on the single ioremap done
* before.
*/
- qdev->main_mem_slot = setup_slot(qdev, 0,
- (unsigned long)qdev->vram_base,
- (unsigned long)qdev->vram_base + qdev->rom->ram_header_offset);
- qdev->surfaces_mem_slot = setup_slot(qdev, 1,
- (unsigned long)qdev->surfaceram_base,
- (unsigned long)qdev->surfaceram_base + qdev->surfaceram_size);
- DRM_INFO("main mem slot %d [%lx,%x]\n",
- qdev->main_mem_slot,
- (unsigned long)qdev->vram_base, qdev->rom->ram_header_offset);
- DRM_INFO("surface mem slot %d [%lx,%lx]\n",
- qdev->surfaces_mem_slot,
- (unsigned long)qdev->surfaceram_base,
- (unsigned long)qdev->surfaceram_size);
+ setup_slot(qdev, &qdev->main_slot, 0, "main",
+ (unsigned long)qdev->vram_base,
+ (unsigned long)qdev->rom->ram_header_offset);
+ setup_slot(qdev, &qdev->surfaces_slot, 1, "surfaces",
+ (unsigned long)qdev->surfaceram_base,
+ (unsigned long)qdev->surfaceram_size);
INIT_WORK(&qdev->gc_work, qxl_gc_work);
return 0;
-mem_slots_free:
- kfree(qdev->mem_slots);
release_ring_free:
qxl_ring_free(qdev->release_ring);
cursor_ring_free:
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 91f3bbc73ecc..4928fa602944 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -36,6 +36,7 @@ static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)
qdev = (struct qxl_device *)bo->gem_base.dev->dev_private;
qxl_surface_evict(qdev, bo, false);
+ WARN_ON_ONCE(bo->map_count > 0);
mutex_lock(&qdev->gem.mutex);
list_del_init(&bo->list);
mutex_unlock(&qdev->gem.mutex);
@@ -60,8 +61,10 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
qbo->placement.busy_placement = qbo->placements;
if (domain == QXL_GEM_DOMAIN_VRAM)
qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
- if (domain == QXL_GEM_DOMAIN_SURFACE)
+ if (domain == QXL_GEM_DOMAIN_SURFACE) {
qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV | pflag;
+ qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
+ }
if (domain == QXL_GEM_DOMAIN_CPU)
qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
if (!c)
@@ -129,6 +132,7 @@ int qxl_bo_kmap(struct qxl_bo *bo, void **ptr)
if (bo->kptr) {
if (ptr)
*ptr = bo->kptr;
+ bo->map_count++;
return 0;
}
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap);
@@ -137,6 +141,7 @@ int qxl_bo_kmap(struct qxl_bo *bo, void **ptr)
bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
if (ptr)
*ptr = bo->kptr;
+ bo->map_count = 1;
return 0;
}
@@ -178,6 +183,9 @@ void qxl_bo_kunmap(struct qxl_bo *bo)
{
if (bo->kptr == NULL)
return;
+ bo->map_count--;
+ if (bo->map_count > 0)
+ return;
bo->kptr = NULL;
ttm_bo_kunmap(&bo->kmap);
}
@@ -332,7 +340,7 @@ int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
if (ret)
return ret;
- ret = qxl_hw_surface_alloc(qdev, bo, NULL);
+ ret = qxl_hw_surface_alloc(qdev, bo);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
index a55dece118b2..8b448eca1cd9 100644
--- a/drivers/gpu/drm/qxl/qxl_prime.c
+++ b/drivers/gpu/drm/qxl/qxl_prime.c
@@ -23,44 +23,43 @@
*/
#include "qxl_drv.h"
+#include "qxl_object.h"
/* Empty Implementations as there should not be any other driver for a virtual
* device that might share buffers with qxl */
int qxl_gem_prime_pin(struct drm_gem_object *obj)
{
- WARN_ONCE(1, "not implemented");
- return -ENOSYS;
-}
+ struct qxl_bo *bo = gem_to_qxl_bo(obj);
-void qxl_gem_prime_unpin(struct drm_gem_object *obj)
-{
- WARN_ONCE(1, "not implemented");
+ return qxl_bo_pin(bo);
}
-struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
+void qxl_gem_prime_unpin(struct drm_gem_object *obj)
{
- WARN_ONCE(1, "not implemented");
- return ERR_PTR(-ENOSYS);
-}
+ struct qxl_bo *bo = gem_to_qxl_bo(obj);
-struct drm_gem_object *qxl_gem_prime_import_sg_table(
- struct drm_device *dev, struct dma_buf_attachment *attach,
- struct sg_table *table)
-{
- WARN_ONCE(1, "not implemented");
- return ERR_PTR(-ENOSYS);
+ qxl_bo_unpin(bo);
}
void *qxl_gem_prime_vmap(struct drm_gem_object *obj)
{
- WARN_ONCE(1, "not implemented");
- return ERR_PTR(-ENOSYS);
+ struct qxl_bo *bo = gem_to_qxl_bo(obj);
+ void *ptr;
+ int ret;
+
+ ret = qxl_bo_kmap(bo, &ptr);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return ptr;
}
void qxl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
- WARN_ONCE(1, "not implemented");
+ struct qxl_bo *bo = gem_to_qxl_bo(obj);
+
+ qxl_bo_kunmap(bo);
}
int qxl_gem_prime_mmap(struct drm_gem_object *obj,
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 886f61e94f24..92f5db5b296f 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -100,6 +100,11 @@ static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
struct ttm_mem_type_manager *man)
{
+ struct qxl_device *qdev = qxl_get_qdev(bdev);
+ unsigned int gpu_offset_shift =
+ 64 - (qdev->rom->slot_gen_bits + qdev->rom->slot_id_bits + 8);
+ struct qxl_memslot *slot;
+
switch (type) {
case TTM_PL_SYSTEM:
/* System memory */
@@ -110,8 +115,11 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
case TTM_PL_VRAM:
case TTM_PL_PRIV:
/* "On-card" video ram */
+ slot = (type == TTM_PL_VRAM) ?
+ &qdev->main_slot : &qdev->surfaces_slot;
+ slot->gpu_offset = (uint64_t)type << gpu_offset_shift;
man->func = &ttm_bo_manager_func;
- man->gpu_offset = 0;
+ man->gpu_offset = slot->gpu_offset;
man->flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_MAPPABLE;
man->available_caching = TTM_PL_MASK_CACHING;
@@ -196,7 +204,7 @@ static void qxl_ttm_io_mem_free(struct ttm_bo_device *bdev,
* TTM backend functions.
*/
struct qxl_ttm_tt {
- struct ttm_dma_tt ttm;
+ struct ttm_tt ttm;
struct qxl_device *qdev;
u64 offset;
};
@@ -225,7 +233,7 @@ static void qxl_ttm_backend_destroy(struct ttm_tt *ttm)
{
struct qxl_ttm_tt *gtt = (void *)ttm;
- ttm_dma_tt_fini(&gtt->ttm);
+ ttm_tt_fini(&gtt->ttm);
kfree(gtt);
}
@@ -245,13 +253,13 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
gtt = kzalloc(sizeof(struct qxl_ttm_tt), GFP_KERNEL);
if (gtt == NULL)
return NULL;
- gtt->ttm.ttm.func = &qxl_backend_func;
+ gtt->ttm.func = &qxl_backend_func;
gtt->qdev = qdev;
- if (ttm_dma_tt_init(&gtt->ttm, bo, page_flags)) {
+ if (ttm_tt_init(&gtt->ttm, bo, page_flags)) {
kfree(gtt);
return NULL;
}
- return &gtt->ttm.ttm;
+ return &gtt->ttm;
}
static void qxl_move_null(struct ttm_buffer_object *bo,
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 0d2b7e42b3a7..4b1a505ab353 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -57,7 +57,7 @@ static const struct file_operations r128_driver_fops = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_LEGACY |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ,
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
.load = r128_driver_load,
.preclose = r128_driver_preclose,
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index d587779a80b4..a97294ac96d5 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -5676,7 +5676,7 @@ int ci_dpm_init(struct radeon_device *rdev)
u16 data_offset, size;
u8 frev, crev;
struct ci_power_info *pi;
- enum pci_bus_speed speed_cap;
+ enum pci_bus_speed speed_cap = PCI_SPEED_UNKNOWN;
struct pci_dev *root = rdev->pdev->bus->self;
int ret;
@@ -5685,7 +5685,8 @@ int ci_dpm_init(struct radeon_device *rdev)
return -ENOMEM;
rdev->pm.dpm.priv = pi;
- speed_cap = pcie_get_speed_cap(root);
+ if (!pci_is_root_bus(rdev->pdev->bus))
+ speed_cap = pcie_get_speed_cap(root);
if (speed_cap == PCI_SPEED_UNKNOWN) {
pi->sys_pcie_mask = 0;
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 8d3251a10cd4..224cc21bbe38 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -29,6 +29,7 @@
#include <acpi/video.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "radeon.h"
#include "radeon_acpi.h"
#include "atom.h"
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 414642e5b7a3..de1745adcccc 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -28,6 +28,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_audio.h"
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 59c8a6647ff2..53f29a115104 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_cache.h>
#include <drm/radeon_drm.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index b190478ad087..aa898c699101 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -35,6 +35,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_edid.h>
#include <linux/gcd.h>
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
index a0c70e27ab65..8d85540bbb43 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -3,6 +3,7 @@
#include <drm/drmP.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include "radeon.h"
#include "atom.h"
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 99c63eeb2866..2e96c886392b 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -43,6 +43,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
/*
* KMS wrapper.
@@ -533,9 +534,7 @@ radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
static struct drm_driver kms_driver = {
.driver_features =
- DRIVER_USE_AGP |
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
- DRIVER_PRIME | DRIVER_RENDER,
+ DRIVER_USE_AGP | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER,
.load = radeon_driver_load_kms,
.open = radeon_driver_open_kms,
.postclose = radeon_driver_postclose_kms,
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index afaf10db47cc..1d5e3ba7383e 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -27,6 +27,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/radeon_drm.h>
#include "radeon_reg.h"
#include "radeon.h"
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 8fb60b3af015..0a785ef0ab66 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -6899,7 +6899,7 @@ int si_dpm_init(struct radeon_device *rdev)
struct ni_power_info *ni_pi;
struct si_power_info *si_pi;
struct atom_clock_dividers dividers;
- enum pci_bus_speed speed_cap;
+ enum pci_bus_speed speed_cap = PCI_SPEED_UNKNOWN;
struct pci_dev *root = rdev->pdev->bus->self;
int ret;
@@ -6911,7 +6911,8 @@ int si_dpm_init(struct radeon_device *rdev)
eg_pi = &ni_pi->eg;
pi = &eg_pi->rv7xx;
- speed_cap = pcie_get_speed_cap(root);
+ if (!pci_is_root_bus(rdev->pdev->bus))
+ speed_cap = pcie_get_speed_cap(root);
if (speed_cap == PCI_SPEED_UNKNOWN) {
si_pi->sys_pcie_mask = 0;
} else {
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 225141656e19..7c36e2777a15 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -4,6 +4,7 @@ config DRM_RCAR_DU
depends on DRM && OF
depends on ARM || ARM64
depends on ARCH_RENESAS || COMPILE_TEST
+ imply DRM_RCAR_LVDS
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 771b460c7216..4cdea14d552f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -9,15 +9,17 @@
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
#include "rcar_du_crtc.h"
#include "rcar_du_drv.h"
@@ -26,6 +28,7 @@
#include "rcar_du_plane.h"
#include "rcar_du_regs.h"
#include "rcar_du_vsp.h"
+#include "rcar_lvds.h"
static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
{
@@ -657,8 +660,27 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state);
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
rcar_du_crtc_get(rcrtc);
+
+ /*
+ * On D3/E3 the dot clock is provided by the LVDS encoder attached to
+ * the DU channel. We need to enable its clock output explicitly if
+ * the LVDS output is disabled.
+ */
+ if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) &&
+ rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
+ struct rcar_du_encoder *encoder =
+ rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
+ const struct drm_display_mode *mode =
+ &crtc->state->adjusted_mode;
+
+ rcar_lvds_clk_enable(encoder->base.bridge,
+ mode->clock * 1000);
+ }
+
rcar_du_crtc_start(rcrtc);
}
@@ -666,10 +688,24 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(old_state);
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
rcar_du_crtc_stop(rcrtc);
rcar_du_crtc_put(rcrtc);
+ if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) &&
+ rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
+ struct rcar_du_encoder *encoder =
+ rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
+
+ /*
+ * Disable the LVDS clock output, see
+ * rcar_du_crtc_atomic_enable().
+ */
+ rcar_lvds_clk_disable(encoder->base.bridge);
+ }
+
spin_lock_irq(&crtc->dev->event_lock);
if (crtc->state->event) {
drm_crtc_send_vblank_event(crtc, crtc->state->event);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index d1f305694367..75ab17af13a9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -18,10 +18,11 @@
#include <linux/wait.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_probe_helper.h>
#include "rcar_du_drv.h"
#include "rcar_du_kms.h"
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 6c187d0bf7c2..1327cd0df90a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -22,6 +22,7 @@ struct device;
struct drm_device;
struct drm_property;
struct rcar_du_device;
+struct rcar_du_encoder;
#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0) /* Per-CRTC IRQ and clock */
#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(1) /* Has inputs from VSP1 */
@@ -81,6 +82,8 @@ struct rcar_du_device {
struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
unsigned int num_crtcs;
+ struct rcar_du_encoder *encoders[RCAR_DU_OUTPUT_MAX];
+
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index f16209499117..8ee4e762f4e5 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -10,7 +10,7 @@
#include <linux/export.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include "rcar_du_drv.h"
@@ -30,8 +30,7 @@ static const struct drm_encoder_funcs encoder_funcs = {
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output,
- struct device_node *enc_node,
- struct device_node *con_node)
+ struct device_node *enc_node)
{
struct rcar_du_encoder *renc;
struct drm_encoder *encoder;
@@ -42,6 +41,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
if (renc == NULL)
return -ENOMEM;
+ rcdu->encoders[output] = renc;
renc->output = output;
encoder = rcar_encoder_to_drm_encoder(renc);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 552f2a02e5b5..df9be4524301 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -26,7 +26,6 @@ struct rcar_du_encoder {
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output,
- struct device_node *enc_node,
- struct device_node *con_node);
+ struct device_node *enc_node);
#endif /* __RCAR_DU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index e4b248e368d6..3b7d50a8fb9b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -10,10 +10,12 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
#include <linux/of_graph.h>
#include <linux/wait.h>
@@ -330,17 +332,10 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
enum rcar_du_output output,
struct of_endpoint *ep)
{
- struct device_node *connector = NULL;
- struct device_node *encoder = NULL;
- struct device_node *ep_node = NULL;
- struct device_node *entity_ep_node;
struct device_node *entity;
int ret;
- /*
- * Locate the connected entity and infer its type from the number of
- * endpoints.
- */
+ /* Locate the connected entity and initialize the encoder. */
entity = of_graph_get_remote_port_parent(ep->local_node);
if (!entity) {
dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n",
@@ -352,52 +347,17 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
dev_dbg(rcdu->dev,
"connected entity %pOF is disabled, skipping\n",
entity);
+ of_node_put(entity);
return -ENODEV;
}
- entity_ep_node = of_graph_get_remote_endpoint(ep->local_node);
-
- for_each_endpoint_of_node(entity, ep_node) {
- if (ep_node == entity_ep_node)
- continue;
-
- /*
- * We've found one endpoint other than the input, this must
- * be an encoder. Locate the connector.
- */
- encoder = entity;
- connector = of_graph_get_remote_port_parent(ep_node);
- of_node_put(ep_node);
-
- if (!connector) {
- dev_warn(rcdu->dev,
- "no connector for encoder %pOF, skipping\n",
- encoder);
- of_node_put(entity_ep_node);
- of_node_put(encoder);
- return -ENODEV;
- }
-
- break;
- }
-
- of_node_put(entity_ep_node);
-
- if (!encoder) {
- dev_warn(rcdu->dev,
- "no encoder found for endpoint %pOF, skipping\n",
- ep->local_node);
- return -ENODEV;
- }
-
- ret = rcar_du_encoder_init(rcdu, output, encoder, connector);
+ ret = rcar_du_encoder_init(rcdu, output, entity);
if (ret && ret != -EPROBE_DEFER)
dev_warn(rcdu->dev,
"failed to initialize encoder %pOF on output %u (%d), skipping\n",
- encoder, output, ret);
+ entity, output, ret);
- of_node_put(encoder);
- of_node_put(connector);
+ of_node_put(entity);
return ret;
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index fa6b9aabc832..c6430027169f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -10,8 +10,9 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index dec314a687e0..0878accbd134 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -9,11 +9,11 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index 96d749a35b25..7ef97b2a6eda 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
@@ -19,9 +20,10 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+#include "rcar_lvds.h"
#include "rcar_lvds_regs.h"
struct rcar_lvds;
@@ -182,8 +184,9 @@ struct pll_info {
static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
unsigned long target, struct pll_info *pll,
- u32 clksel)
+ u32 clksel, bool dot_clock_only)
{
+ unsigned int div7 = dot_clock_only ? 1 : 7;
unsigned long output;
unsigned long fin;
unsigned int m_min;
@@ -217,9 +220,9 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
* `------------> | |
* |/
*
- * The /7 divider is optional when the LVDS PLL is used to generate a
- * dot clock for the DU RGB output, without using the LVDS encoder. We
- * don't support this configuration yet.
+ * The /7 divider is optional, it is enabled when the LVDS PLL is used
+ * to drive the LVDS encoder, and disabled when used to generate a dot
+ * clock for the DU RGB output, without using the LVDS encoder.
*
* The PLL allowed input frequency range is 12 MHz to 192 MHz.
*/
@@ -279,7 +282,7 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
* the PLL, followed by a an optional fixed /7
* divider.
*/
- fout = fvco / (1 << e) / 7;
+ fout = fvco / (1 << e) / div7;
div = DIV_ROUND_CLOSEST(fout, target);
diff = abs(fout / div - target);
@@ -300,7 +303,7 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
done:
output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
- / 7 / pll->div;
+ / div7 / pll->div;
error = (long)(output - target) * 10000 / (long)target;
dev_dbg(lvds->dev,
@@ -310,17 +313,18 @@ done:
pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
}
-static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
+static void __rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds,
+ unsigned int freq, bool dot_clock_only)
{
struct pll_info pll = { .diff = (unsigned long)-1 };
u32 lvdpllcr;
rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
- LVDPLLCR_CKSEL_DU_DOTCLKIN(0));
+ LVDPLLCR_CKSEL_DU_DOTCLKIN(0), dot_clock_only);
rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
- LVDPLLCR_CKSEL_DU_DOTCLKIN(1));
+ LVDPLLCR_CKSEL_DU_DOTCLKIN(1), dot_clock_only);
rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
- LVDPLLCR_CKSEL_EXTAL);
+ LVDPLLCR_CKSEL_EXTAL, dot_clock_only);
lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
| LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);
@@ -329,6 +333,9 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
| LVDPLLCR_PLLE(pll.pll_e - 1);
+ if (dot_clock_only)
+ lvdpllcr |= LVDPLLCR_OCKSEL;
+
rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
if (pll.div > 1)
@@ -342,6 +349,57 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
rcar_lvds_write(lvds, LVDDIV, 0);
}
+static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
+{
+ __rcar_lvds_pll_setup_d3_e3(lvds, freq, false);
+}
+
+/* -----------------------------------------------------------------------------
+ * Clock - D3/E3 only
+ */
+
+int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq)
+{
+ struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+ int ret;
+
+ if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
+ return -ENODEV;
+
+ dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
+
+ WARN_ON(lvds->enabled);
+
+ ret = clk_prepare_enable(lvds->clocks.mod);
+ if (ret < 0)
+ return ret;
+
+ __rcar_lvds_pll_setup_d3_e3(lvds, freq, true);
+
+ lvds->enabled = true;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rcar_lvds_clk_enable);
+
+void rcar_lvds_clk_disable(struct drm_bridge *bridge)
+{
+ struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+
+ if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
+ return;
+
+ dev_dbg(lvds->dev, "disabling LVDS PLL\n");
+
+ WARN_ON(!lvds->enabled);
+
+ rcar_lvds_write(lvds, LVDPLLCR, 0);
+
+ clk_disable_unprepare(lvds->clocks.mod);
+
+ lvds->enabled = false;
+}
+EXPORT_SYMBOL_GPL(rcar_lvds_clk_disable);
+
/* -----------------------------------------------------------------------------
* Bridge
*/
@@ -544,7 +602,10 @@ static int rcar_lvds_attach(struct drm_bridge *bridge)
return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
bridge);
- /* Otherwise we have a panel, create a connector. */
+ /* Otherwise if we have a panel, create a connector. */
+ if (!lvds->panel)
+ return 0;
+
ret = drm_connector_init(bridge->dev, connector, &rcar_lvds_conn_funcs,
DRM_MODE_CONNECTOR_LVDS);
if (ret < 0)
@@ -592,7 +653,8 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
local_output = of_graph_get_endpoint_by_regs(lvds->dev->of_node, 1, 0);
if (!local_output) {
dev_dbg(lvds->dev, "unconnected port@1\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto done;
}
/*
@@ -642,6 +704,15 @@ done:
of_node_put(remote_input);
of_node_put(remote);
+ /*
+ * On D3/E3 the LVDS encoder provides a clock to the DU, which can be
+ * used for the DPAD output even when the LVDS output is not connected.
+ * Don't fail probe in that case as the DU will need the bridge to
+ * control the clock.
+ */
+ if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)
+ return ret == -ENODEV ? 0 : ret;
+
return ret;
}
@@ -785,6 +856,7 @@ static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = {
static const struct of_device_id rcar_lvds_of_table[] = {
{ .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info },
+ { .compatible = "renesas,r8a7744-lvds", .data = &rcar_lvds_gen2_info },
{ .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info },
{ .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_r8a7790_info },
{ .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h
new file mode 100644
index 000000000000..a709cae1bc32
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * rcar_lvds.h -- R-Car LVDS Encoder
+ *
+ * Copyright (C) 2013-2018 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ */
+
+#ifndef __RCAR_LVDS_H__
+#define __RCAR_LVDS_H__
+
+struct drm_bridge;
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
+int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq);
+void rcar_lvds_clk_disable(struct drm_bridge *bridge);
+#else
+static inline int rcar_lvds_clk_enable(struct drm_bridge *bridge,
+ unsigned long freq)
+{
+ return -ENOSYS;
+}
+static inline void rcar_lvds_clk_disable(struct drm_bridge *bridge) { }
+#endif /* CONFIG_DRM_RCAR_LVDS */
+
+#endif /* __RCAR_LVDS_H__ */
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 080f05352195..bc4423624209 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -21,10 +21,10 @@
#include <linux/clk.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 8ad0d773dc33..f7b9d45aa1d6 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -14,10 +14,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index f57e296401b8..48fef95cb3c6 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -16,9 +16,9 @@
#define _CDN_DP_CORE_H
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
#define MAX_PHY 2
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
index 5a485489a1e2..6c8b14fb1d2f 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -113,7 +113,7 @@ static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val)
static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
u8 module_id, u8 opcode,
- u8 req_size)
+ u16 req_size)
{
u32 mbox_size, i;
u8 header[4];
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 89c63cfde5c8..4cdc9f86c2e5 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -16,8 +16,8 @@
#include <drm/drm_of.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_hdmi.h>
#include "rockchip_drm_drv.h"
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 27c945e030a0..ce1545862b6c 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -26,8 +26,8 @@
#include <drm/drm_of.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_vop.h"
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index be6c2573039a..d7fa17f12769 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -15,10 +15,10 @@
*/
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/dma-mapping.h>
#include <linux/dma-iommu.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 08bec50d9c5d..97438bbbe389 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -17,8 +17,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_fb.h"
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
index e6650553f5d6..8ce68bd508be 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
@@ -15,7 +15,7 @@
#include <drm/drm.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
@@ -91,7 +91,6 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
}
fbi->par = helper;
- fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->fbops = &rockchip_drm_fbdev_ops;
fb = helper->fb;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 22a70ab6e214..a0c8bd235b67 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -14,7 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_psr.h"
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 619b6db05d58..c7d4c6073ea5 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -17,10 +17,10 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#ifdef CONFIG_DRM_ANALOGIX_DP
#include <drm/bridge/analogix_dp.h>
#endif
@@ -1675,7 +1675,9 @@ static void vop_win_init(struct vop *vop)
vop_win->data = win_data;
vop_win->vop = vop;
- vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i];
+
+ if (vop_data->win_yuv2yuv)
+ vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i];
}
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 456bd9f13bae..e52dd5a8529e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -16,10 +16,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index 96ac1458a59c..ce4d82d293e4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -1,25 +1,16 @@
-//SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author:
* Sandy Huang <hjc@rock-chips.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
#include <linux/of_graph.h>
@@ -113,8 +104,10 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
child_count++;
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id,
&panel, &bridge);
- if (!ret)
+ if (!ret) {
+ of_node_put(endpoint);
break;
+ }
}
of_node_put(port);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.h b/drivers/gpu/drm/rockchip/rockchip_rgb.h
index 38b52e63b2b0..27b9635124bc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.h
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.h
@@ -1,17 +1,8 @@
-//SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author:
* Sandy Huang <hjc@rock-chips.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifdef CONFIG_ROCKCHIP_RGB
diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c
index 7559a820bd43..ebb8b7d32b33 100644
--- a/drivers/gpu/drm/savage/savage_state.c
+++ b/drivers/gpu/drm/savage/savage_state.c
@@ -299,6 +299,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST_201:
reorder = 1;
prim = SAVAGE_PRIM_TRILIST;
+ /* fall through */
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
@@ -436,6 +437,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST_201:
reorder = 1;
prim = SAVAGE_PRIM_TRILIST;
+ /* fall through */
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
@@ -557,6 +559,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST_201:
reorder = 1;
prim = SAVAGE_PRIM_TRILIST;
+ /* fall through */
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
@@ -695,6 +698,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST_201:
reorder = 1;
prim = SAVAGE_PRIM_TRILIST;
+ /* fall through */
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index 4463d3826ecb..e2942c9a11a7 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -440,13 +440,10 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
while ((entity->dependency =
sched->ops->dependency(sched_job, entity))) {
+ trace_drm_sched_job_wait_dep(sched_job, entity->dependency);
- if (drm_sched_entity_add_dependency_cb(entity)) {
-
- trace_drm_sched_job_wait_dep(sched_job,
- entity->dependency);
+ if (drm_sched_entity_add_dependency_cb(entity))
return NULL;
- }
}
/* skip jobs from entity that marked guilty */
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index dbb69063b3d5..19fc601c9eeb 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -60,8 +60,6 @@
static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb);
-static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job);
-
/**
* drm_sched_rq_init - initialize a given run queue struct
*
@@ -286,8 +284,6 @@ static void drm_sched_job_finish(struct work_struct *work)
cancel_delayed_work_sync(&sched->work_tdr);
spin_lock_irqsave(&sched->job_list_lock, flags);
- /* remove job from ring_mirror_list */
- list_del_init(&s_job->node);
/* queue TDR for next job */
drm_sched_start_timeout(sched);
spin_unlock_irqrestore(&sched->job_list_lock, flags);
@@ -295,22 +291,11 @@ static void drm_sched_job_finish(struct work_struct *work)
sched->ops->free_job(s_job);
}
-static void drm_sched_job_finish_cb(struct dma_fence *f,
- struct dma_fence_cb *cb)
-{
- struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
- finish_cb);
- schedule_work(&job->finish_work);
-}
-
static void drm_sched_job_begin(struct drm_sched_job *s_job)
{
struct drm_gpu_scheduler *sched = s_job->sched;
unsigned long flags;
- dma_fence_add_callback(&s_job->s_fence->finished, &s_job->finish_cb,
- drm_sched_job_finish_cb);
-
spin_lock_irqsave(&sched->job_list_lock, flags);
list_add_tail(&s_job->node, &sched->ring_mirror_list);
drm_sched_start_timeout(sched);
@@ -335,6 +320,51 @@ static void drm_sched_job_timedout(struct work_struct *work)
spin_unlock_irqrestore(&sched->job_list_lock, flags);
}
+ /**
+ * drm_sched_increase_karma - Update sched_entity guilty flag
+ *
+ * @bad: The job guilty of time out
+ *
+ * Increment on every hang caused by the 'bad' job. If this exceeds the hang
+ * limit of the scheduler then the respective sched entity is marked guilty and
+ * jobs from it will not be scheduled further
+ */
+void drm_sched_increase_karma(struct drm_sched_job *bad)
+{
+ int i;
+ struct drm_sched_entity *tmp;
+ struct drm_sched_entity *entity;
+ struct drm_gpu_scheduler *sched = bad->sched;
+
+ /* don't increase @bad's karma if it's from KERNEL RQ,
+ * because sometimes GPU hang would cause kernel jobs (like VM updating jobs)
+ * corrupt but keep in mind that kernel jobs always considered good.
+ */
+ if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
+ atomic_inc(&bad->karma);
+ for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL;
+ i++) {
+ struct drm_sched_rq *rq = &sched->sched_rq[i];
+
+ spin_lock(&rq->lock);
+ list_for_each_entry_safe(entity, tmp, &rq->entities, list) {
+ if (bad->s_fence->scheduled.context ==
+ entity->fence_context) {
+ if (atomic_read(&bad->karma) >
+ bad->sched->hang_limit)
+ if (entity->guilty)
+ atomic_set(entity->guilty, 1);
+ break;
+ }
+ }
+ spin_unlock(&rq->lock);
+ if (&entity->list != &rq->entities)
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(drm_sched_increase_karma);
+
/**
* drm_sched_hw_job_reset - stop the scheduler if it contains the bad job
*
@@ -342,50 +372,42 @@ static void drm_sched_job_timedout(struct work_struct *work)
* @bad: bad scheduler job
*
*/
-void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad)
+void drm_sched_stop(struct drm_gpu_scheduler *sched)
{
struct drm_sched_job *s_job;
- struct drm_sched_entity *entity, *tmp;
unsigned long flags;
- int i;
+ struct dma_fence *last_fence = NULL;
+ kthread_park(sched->thread);
+
+ /*
+ * Verify all the signaled jobs in mirror list are removed from the ring
+ * by waiting for the latest job to enter the list. This should insure that
+ * also all the previous jobs that were in flight also already singaled
+ * and removed from the list.
+ */
spin_lock_irqsave(&sched->job_list_lock, flags);
list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) {
if (s_job->s_fence->parent &&
dma_fence_remove_callback(s_job->s_fence->parent,
- &s_job->s_fence->cb)) {
+ &s_job->cb)) {
dma_fence_put(s_job->s_fence->parent);
s_job->s_fence->parent = NULL;
atomic_dec(&sched->hw_rq_count);
+ } else {
+ last_fence = dma_fence_get(&s_job->s_fence->finished);
+ break;
}
}
spin_unlock_irqrestore(&sched->job_list_lock, flags);
- if (bad && bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
- atomic_inc(&bad->karma);
- /* don't increase @bad's karma if it's from KERNEL RQ,
- * becuase sometimes GPU hang would cause kernel jobs (like VM updating jobs)
- * corrupt but keep in mind that kernel jobs always considered good.
- */
- for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL; i++ ) {
- struct drm_sched_rq *rq = &sched->sched_rq[i];
-
- spin_lock(&rq->lock);
- list_for_each_entry_safe(entity, tmp, &rq->entities, list) {
- if (bad->s_fence->scheduled.context == entity->fence_context) {
- if (atomic_read(&bad->karma) > bad->sched->hang_limit)
- if (entity->guilty)
- atomic_set(entity->guilty, 1);
- break;
- }
- }
- spin_unlock(&rq->lock);
- if (&entity->list != &rq->entities)
- break;
- }
+ if (last_fence) {
+ dma_fence_wait(last_fence, false);
+ dma_fence_put(last_fence);
}
}
-EXPORT_SYMBOL(drm_sched_hw_job_reset);
+
+EXPORT_SYMBOL(drm_sched_stop);
/**
* drm_sched_job_recovery - recover jobs after a reset
@@ -393,18 +415,58 @@ EXPORT_SYMBOL(drm_sched_hw_job_reset);
* @sched: scheduler instance
*
*/
-void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
+void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery)
{
struct drm_sched_job *s_job, *tmp;
- bool found_guilty = false;
- unsigned long flags;
int r;
- spin_lock_irqsave(&sched->job_list_lock, flags);
+ if (!full_recovery)
+ goto unpark;
+
+ /*
+ * Locking the list is not required here as the sched thread is parked
+ * so no new jobs are being pushed in to HW and in drm_sched_stop we
+ * flushed all the jobs who were still in mirror list but who already
+ * signaled and removed them self from the list. Also concurrent
+ * GPU recovers can't run in parallel.
+ */
+ list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
+ struct dma_fence *fence = s_job->s_fence->parent;
+
+ if (fence) {
+ r = dma_fence_add_callback(fence, &s_job->cb,
+ drm_sched_process_job);
+ if (r == -ENOENT)
+ drm_sched_process_job(fence, &s_job->cb);
+ else if (r)
+ DRM_ERROR("fence add callback failed (%d)\n",
+ r);
+ } else
+ drm_sched_process_job(NULL, &s_job->cb);
+ }
+
+ drm_sched_start_timeout(sched);
+
+unpark:
+ kthread_unpark(sched->thread);
+}
+EXPORT_SYMBOL(drm_sched_start);
+
+/**
+ * drm_sched_resubmit_jobs - helper to relunch job from mirror ring list
+ *
+ * @sched: scheduler instance
+ *
+ */
+void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
+{
+ struct drm_sched_job *s_job, *tmp;
+ uint64_t guilty_context;
+ bool found_guilty = false;
+
+ /*TODO DO we need spinlock here ? */
list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
struct drm_sched_fence *s_fence = s_job->s_fence;
- struct dma_fence *fence;
- uint64_t guilty_context;
if (!found_guilty && atomic_read(&s_job->karma) > sched->hang_limit) {
found_guilty = true;
@@ -414,31 +476,11 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
if (found_guilty && s_job->s_fence->scheduled.context == guilty_context)
dma_fence_set_error(&s_fence->finished, -ECANCELED);
- spin_unlock_irqrestore(&sched->job_list_lock, flags);
- fence = sched->ops->run_job(s_job);
+ s_job->s_fence->parent = sched->ops->run_job(s_job);
atomic_inc(&sched->hw_rq_count);
-
- if (fence) {
- s_fence->parent = dma_fence_get(fence);
- r = dma_fence_add_callback(fence, &s_fence->cb,
- drm_sched_process_job);
- if (r == -ENOENT)
- drm_sched_process_job(fence, &s_fence->cb);
- else if (r)
- DRM_ERROR("fence add callback failed (%d)\n",
- r);
- dma_fence_put(fence);
- } else {
- if (s_fence->finished.error < 0)
- drm_sched_expel_job_unlocked(s_job);
- drm_sched_process_job(NULL, &s_fence->cb);
- }
- spin_lock_irqsave(&sched->job_list_lock, flags);
}
- drm_sched_start_timeout(sched);
- spin_unlock_irqrestore(&sched->job_list_lock, flags);
}
-EXPORT_SYMBOL(drm_sched_job_recovery);
+EXPORT_SYMBOL(drm_sched_resubmit_jobs);
/**
* drm_sched_job_init - init a scheduler job
@@ -552,18 +594,27 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched)
*/
static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb)
{
- struct drm_sched_fence *s_fence =
- container_of(cb, struct drm_sched_fence, cb);
+ struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb);
+ struct drm_sched_fence *s_fence = s_job->s_fence;
struct drm_gpu_scheduler *sched = s_fence->sched;
+ unsigned long flags;
+
+ cancel_delayed_work(&sched->work_tdr);
- dma_fence_get(&s_fence->finished);
atomic_dec(&sched->hw_rq_count);
atomic_dec(&sched->num_jobs);
+
+ spin_lock_irqsave(&sched->job_list_lock, flags);
+ /* remove job from ring_mirror_list */
+ list_del_init(&s_job->node);
+ spin_unlock_irqrestore(&sched->job_list_lock, flags);
+
drm_sched_fence_finished(s_fence);
trace_drm_sched_process_job(s_fence);
- dma_fence_put(&s_fence->finished);
wake_up_interruptible(&sched->wake_up_worker);
+
+ schedule_work(&s_job->finish_work);
}
/**
@@ -626,34 +677,22 @@ static int drm_sched_main(void *param)
if (fence) {
s_fence->parent = dma_fence_get(fence);
- r = dma_fence_add_callback(fence, &s_fence->cb,
+ r = dma_fence_add_callback(fence, &sched_job->cb,
drm_sched_process_job);
if (r == -ENOENT)
- drm_sched_process_job(fence, &s_fence->cb);
+ drm_sched_process_job(fence, &sched_job->cb);
else if (r)
DRM_ERROR("fence add callback failed (%d)\n",
r);
dma_fence_put(fence);
- } else {
- if (s_fence->finished.error < 0)
- drm_sched_expel_job_unlocked(sched_job);
- drm_sched_process_job(NULL, &s_fence->cb);
- }
+ } else
+ drm_sched_process_job(NULL, &sched_job->cb);
wake_up(&sched->job_scheduled);
}
return 0;
}
-static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job)
-{
- struct drm_gpu_scheduler *sched = s_job->sched;
-
- spin_lock(&sched->job_list_lock);
- list_del_init(&s_job->node);
- spin_unlock(&sched->job_list_lock);
-}
-
/**
* drm_sched_init - Init a gpu scheduler instance
*
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 499b5fdb869f..b6988a6d698e 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -16,6 +16,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "shmob_drm_backlight.h"
#include "shmob_drm_crtc.h"
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index f2cfd1698b78..cb821adfc321 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -18,6 +18,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_probe_helper.h>
#include "shmob_drm_drv.h"
#include "shmob_drm_kms.h"
@@ -126,7 +127,7 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg)
DEFINE_DRM_GEM_CMA_FOPS(shmob_drm_fops);
static struct drm_driver shmob_drm_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
+ .driver_features = DRIVER_GEM | DRIVER_MODESET
| DRIVER_PRIME,
.irq_handler = shmob_drm_irq,
.gem_free_object_unlocked = drm_gem_cma_free_object,
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
index a17268444c6d..2e08bc203bf9 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
@@ -13,6 +13,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "shmob_drm_crtc.h"
#include "shmob_drm_drv.h"
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index ec9f87483e39..387f0bed6c1c 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -11,8 +11,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "sti_compositor.h"
#include "sti_crtc.h"
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index ac54e0f9caea..a525fd899f68 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -14,12 +14,12 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include "sti_crtc.h"
#include "sti_drv.h"
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index 6d33772f77eb..b31cc2672d36 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -13,8 +13,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "sti_awg_utils.h"
#include "sti_drv.h"
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index a63dd5eb7081..ff9256673fc8 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -12,7 +12,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
/* HDformatter registers */
#define HDA_ANA_CFG 0x0000
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 458fcb5a93f2..6000df624980 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -15,8 +15,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <sound/hdmi-codec.h>
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index ea4a3b87fa55..c42f2fa7053c 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -15,7 +15,7 @@
#include <linux/seq_file.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "sti_crtc.h"
#include "sti_drv.h"
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index 8dec001b9d37..0a7f933ab007 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -9,15 +9,19 @@
*/
#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
#include <linux/of_platform.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
#include "ltdc.h"
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index a91e04139595..b1741a9d5be2 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -10,18 +10,25 @@
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
-#include <drm/drm_bridge.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index c2c042287c19..1dbbc3a1b763 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -45,10 +45,11 @@ config DRM_SUN6I_DSI
default MACH_SUN8I
select CRC_CCITT
select DRM_MIPI_DSI
+ select PHY_SUN6I_MIPI_DPHY
help
Choose this option if you want have an Allwinner SoC with
MIPI-DSI support. If M is selected the module will be called
- sun6i-dsi
+ sun6i_mipi_dsi.
config DRM_SUN8I_DW_HDMI
tristate "Support for Allwinner version of DesignWare HDMI"
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0eb38ac8e86e..0d04f2447b01 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -24,9 +24,6 @@ sun4i-tcon-y += sun4i_lvds.o
sun4i-tcon-y += sun4i_tcon.o
sun4i-tcon-y += sun4i_rgb.o
-sun6i-dsi-y += sun6i_mipi_dphy.o
-sun6i-dsi-y += sun6i_mipi_dsi.o
-
obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o
obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
@@ -37,7 +34,7 @@ ifdef CONFIG_DRM_SUN4I_BACKEND
obj-$(CONFIG_DRM_SUN4I) += sun4i-frontend.o
endif
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
-obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o
+obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i_mipi_dsi.o
obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 892197f52557..4c0d51f73237 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -14,10 +14,10 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
#include <linux/list.h>
@@ -141,7 +141,6 @@ static const uint32_t sun4i_backend_formats[] = {
DRM_FORMAT_ARGB1555,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_ARGB8888,
- DRM_FORMAT_BGRX8888,
DRM_FORMAT_RGB565,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGBA4444,
@@ -765,17 +764,18 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
remote = of_graph_get_remote_port_parent(ep);
if (!remote)
continue;
+ of_node_put(remote);
/* does this node match any registered engines? */
list_for_each_entry(frontend, &drv->frontend_list, list) {
if (remote == frontend->node) {
- of_node_put(remote);
of_node_put(port);
+ of_node_put(ep);
return frontend;
}
}
}
-
+ of_node_put(port);
return ERR_PTR(-EINVAL);
}
@@ -1013,6 +1013,10 @@ static const struct of_device_id sun4i_backend_of_table[] = {
.data = &sun7i_backend_quirks,
},
{
+ .compatible = "allwinner,sun8i-a23-display-backend",
+ .data = &sun8i_a33_backend_quirks,
+ },
+ {
.compatible = "allwinner,sun8i-a33-display-backend",
.data = &sun8i_a33_backend_quirks,
},
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 3eedf335a935..cdb881e34470 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -13,8 +13,8 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_modes.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk-provider.h>
#include <linux/ioport.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 93da837194cf..3ebd9f5e2719 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -16,11 +16,11 @@
#include <linux/of_reserved_mem.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include "sun4i_drv.h"
#include "sun4i_frontend.h"
@@ -165,6 +165,7 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") ||
+ of_device_is_compatible(node, "allwinner,sun8i-a23-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend");
}
@@ -404,6 +405,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-display-engine" },
{ .compatible = "allwinner,sun6i-a31s-display-engine" },
{ .compatible = "allwinner,sun7i-a20-display-engine" },
+ { .compatible = "allwinner,sun8i-a23-display-engine" },
{ .compatible = "allwinner,sun8i-a33-display-engine" },
{ .compatible = "allwinner,sun8i-a83t-display-engine" },
{ .compatible = "allwinner,sun8i-h3-display-engine" },
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
index e8239d4d4dd5..346c8071bd38 100644
--- a/drivers/gpu/drm/sun4i/sun4i_frontend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -720,6 +720,10 @@ const struct of_device_id sun4i_frontend_of_table[] = {
.data = &sun4i_a10_frontend
},
{
+ .compatible = "allwinner,sun8i-a23-display-frontend",
+ .data = &sun8i_a33_frontend
+ },
+ {
.compatible = "allwinner,sun8i-a33-display-frontend",
.data = &sun8i_a33_frontend
},
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 554a6f4561f3..d18862629301 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -11,7 +11,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_of.h>
@@ -93,6 +93,8 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder)
val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;
writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
+
+ clk_disable_unprepare(hdmi->tmds_clk);
}
static void sun4i_hdmi_enable(struct drm_encoder *encoder)
@@ -103,6 +105,8 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
+ clk_prepare_enable(hdmi->tmds_clk);
+
sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index c5a999ca1d72..a514fe88d441 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -117,6 +117,11 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
static bool sun4i_layer_format_mod_supported(struct drm_plane *plane,
uint32_t format, uint64_t modifier)
{
+ struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
+
+ if (IS_ERR_OR_NULL(layer->backend->frontend))
+ sun4i_backend_format_is_supported(format, modifier);
+
return sun4i_backend_format_is_supported(format, modifier) ||
sun4i_frontend_format_is_supported(format, modifier);
}
@@ -165,6 +170,21 @@ static const uint32_t sun4i_layer_formats[] = {
DRM_FORMAT_YVYU,
};
+static const uint32_t sun4i_backend_layer_formats[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+};
+
static const uint64_t sun4i_layer_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_ALLWINNER_TILED,
@@ -175,6 +195,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
struct sun4i_backend *backend,
enum drm_plane_type type)
{
+ const uint64_t *modifiers = sun4i_layer_modifiers;
+ const uint32_t *formats = sun4i_layer_formats;
+ unsigned int formats_len = ARRAY_SIZE(sun4i_layer_formats);
struct sun4i_layer *layer;
int ret;
@@ -182,12 +205,19 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
+ layer->backend = backend;
+
+ if (IS_ERR_OR_NULL(backend->frontend)) {
+ formats = sun4i_backend_layer_formats;
+ formats_len = ARRAY_SIZE(sun4i_backend_layer_formats);
+ modifiers = NULL;
+ }
+
/* possible crtcs are set later */
ret = drm_universal_plane_init(drm, &layer->plane, 0,
&sun4i_backend_layer_funcs,
- sun4i_layer_formats,
- ARRAY_SIZE(sun4i_layer_formats),
- sun4i_layer_modifiers, type, NULL);
+ formats, formats_len,
+ modifiers, type, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n");
return ERR_PTR(ret);
@@ -195,7 +225,6 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
drm_plane_helper_add(&layer->plane,
&sun4i_backend_layer_helper_funcs);
- layer->backend = backend;
drm_plane_create_alpha_property(&layer->plane);
drm_plane_create_zpos_property(&layer->plane, 0, 0,
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
index e7eb0d1e17be..147b97ed1a09 100644
--- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
@@ -8,9 +8,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "sun4i_crtc.h"
#include "sun4i_tcon.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index f4a22689eb54..cae19e7bbeaa 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -14,9 +14,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "sun4i_crtc.h"
#include "sun4i_tcon.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 0420f5c978b9..7136fc91c603 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -14,11 +14,11 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <uapi/drm/drm_mode.h>
@@ -761,6 +761,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
return PTR_ERR(tcon->sclk0);
}
}
+ clk_prepare_enable(tcon->sclk0);
if (tcon->quirks->has_channel_1) {
tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
@@ -775,6 +776,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
{
+ clk_disable_unprepare(tcon->sclk0);
clk_disable_unprepare(tcon->clk);
}
@@ -1494,6 +1496,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
+ { .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 1a838d208211..e8700a362064 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -18,9 +18,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "sun4i_crtc.h"
#include "sun4i_drv.h"
diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c
index 88eb268fdf73..442094a4af7a 100644
--- a/drivers/gpu/drm/sun4i/sun6i_drc.c
+++ b/drivers/gpu/drm/sun4i/sun6i_drc.c
@@ -101,6 +101,7 @@ static int sun6i_drc_remove(struct platform_device *pdev)
static const struct of_device_id sun6i_drc_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-drc" },
{ .compatible = "allwinner,sun6i-a31s-drc" },
+ { .compatible = "allwinner,sun8i-a23-drc" },
{ .compatible = "allwinner,sun8i-a33-drc" },
{ .compatible = "allwinner,sun9i-a80-drc" },
{ }
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
deleted file mode 100644
index e4d19431fa0e..000000000000
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
+++ /dev/null
@@ -1,292 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2016 Allwinnertech Co., Ltd.
- * Copyright (C) 2017-2018 Bootlin
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- */
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/of_address.h>
-#include <linux/regmap.h>
-#include <linux/reset.h>
-
-#include "sun6i_mipi_dsi.h"
-
-#define SUN6I_DPHY_GCTL_REG 0x00
-#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
-#define SUN6I_DPHY_GCTL_EN BIT(0)
-
-#define SUN6I_DPHY_TX_CTL_REG 0x04
-#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
-
-#define SUN6I_DPHY_TX_TIME0_REG 0x10
-#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
-#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
-#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
-
-#define SUN6I_DPHY_TX_TIME1_REG 0x14
-#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
-#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
-#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
-#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
-
-#define SUN6I_DPHY_TX_TIME2_REG 0x18
-#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
-
-#define SUN6I_DPHY_TX_TIME3_REG 0x1c
-
-#define SUN6I_DPHY_TX_TIME4_REG 0x20
-#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
-#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
-
-#define SUN6I_DPHY_ANA0_REG 0x4c
-#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
-#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
-#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
-#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
-#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
-
-#define SUN6I_DPHY_ANA1_REG 0x50
-#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
-#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
-#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
-
-#define SUN6I_DPHY_ANA2_REG 0x54
-#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
-#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
-#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
-#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
-
-#define SUN6I_DPHY_ANA3_REG 0x58
-#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
-#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
-#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
-#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
-#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
-#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
-#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
-
-#define SUN6I_DPHY_ANA4_REG 0x5c
-#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
-#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
-#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
-#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
-#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
-#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
-#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
-#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
-#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
-
-#define SUN6I_DPHY_DBG5_REG 0xf4
-
-int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
-{
- reset_control_deassert(dphy->reset);
- clk_prepare_enable(dphy->mod_clk);
- clk_set_rate_exclusive(dphy->mod_clk, 150000000);
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
- SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
- SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
- SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
- SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
- SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
- SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
- SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
- SUN6I_DPHY_TX_TIME1_CLK_POST(10));
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
- SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
-
- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
- SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
- SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
-
- regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
- SUN6I_DPHY_GCTL_LANE_NUM(lanes) |
- SUN6I_DPHY_GCTL_EN);
-
- return 0;
-}
-
-int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
-{
- u8 lanes_mask = GENMASK(lanes - 1, 0);
-
- regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
- SUN6I_DPHY_ANA0_REG_PWS |
- SUN6I_DPHY_ANA0_REG_DMPC |
- SUN6I_DPHY_ANA0_REG_SLV(7) |
- SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
- SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
-
- regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
- SUN6I_DPHY_ANA1_REG_CSMPS(1) |
- SUN6I_DPHY_ANA1_REG_SVTT(7));
-
- regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
- SUN6I_DPHY_ANA4_REG_CKDV(1) |
- SUN6I_DPHY_ANA4_REG_TMSC(1) |
- SUN6I_DPHY_ANA4_REG_TMSD(1) |
- SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
- SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
- SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
- SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
- SUN6I_DPHY_ANA4_REG_DMPLVC |
- SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
-
- regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
- SUN6I_DPHY_ANA2_REG_ENIB);
- udelay(5);
-
- regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
- SUN6I_DPHY_ANA3_EN_LDOR |
- SUN6I_DPHY_ANA3_EN_LDOC |
- SUN6I_DPHY_ANA3_EN_LDOD);
- udelay(1);
-
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
- SUN6I_DPHY_ANA3_EN_VTTC |
- SUN6I_DPHY_ANA3_EN_VTTD_MASK,
- SUN6I_DPHY_ANA3_EN_VTTC |
- SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
- udelay(1);
-
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
- SUN6I_DPHY_ANA3_EN_DIV,
- SUN6I_DPHY_ANA3_EN_DIV);
- udelay(1);
-
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
- SUN6I_DPHY_ANA2_EN_CK_CPU,
- SUN6I_DPHY_ANA2_EN_CK_CPU);
- udelay(1);
-
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
- SUN6I_DPHY_ANA1_REG_VTTMODE,
- SUN6I_DPHY_ANA1_REG_VTTMODE);
-
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
- SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
- SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
-
- return 0;
-}
-
-int sun6i_dphy_power_off(struct sun6i_dphy *dphy)
-{
- regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
- SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
-
- return 0;
-}
-
-int sun6i_dphy_exit(struct sun6i_dphy *dphy)
-{
- clk_rate_exclusive_put(dphy->mod_clk);
- clk_disable_unprepare(dphy->mod_clk);
- reset_control_assert(dphy->reset);
-
- return 0;
-}
-
-static struct regmap_config sun6i_dphy_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = SUN6I_DPHY_DBG5_REG,
- .name = "mipi-dphy",
-};
-
-static const struct of_device_id sun6i_dphy_of_table[] = {
- { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
- { }
-};
-
-int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node)
-{
- struct sun6i_dphy *dphy;
- struct resource res;
- void __iomem *regs;
- int ret;
-
- if (!of_match_node(sun6i_dphy_of_table, node)) {
- dev_err(dsi->dev, "Incompatible D-PHY\n");
- return -EINVAL;
- }
-
- dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL);
- if (!dphy)
- return -ENOMEM;
-
- ret = of_address_to_resource(node, 0, &res);
- if (ret) {
- dev_err(dsi->dev, "phy: Couldn't get our resources\n");
- return ret;
- }
-
- regs = devm_ioremap_resource(dsi->dev, &res);
- if (IS_ERR(regs)) {
- dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n");
- return PTR_ERR(regs);
- }
-
- dphy->regs = devm_regmap_init_mmio(dsi->dev, regs,
- &sun6i_dphy_regmap_config);
- if (IS_ERR(dphy->regs)) {
- dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n");
- return PTR_ERR(dphy->regs);
- }
-
- dphy->reset = of_reset_control_get_shared(node, NULL);
- if (IS_ERR(dphy->reset)) {
- dev_err(dsi->dev, "Couldn't get our reset line\n");
- return PTR_ERR(dphy->reset);
- }
-
- dphy->bus_clk = of_clk_get_by_name(node, "bus");
- if (IS_ERR(dphy->bus_clk)) {
- dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n");
- ret = PTR_ERR(dphy->bus_clk);
- goto err_free_reset;
- }
- regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk);
-
- dphy->mod_clk = of_clk_get_by_name(node, "mod");
- if (IS_ERR(dphy->mod_clk)) {
- dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n");
- ret = PTR_ERR(dphy->mod_clk);
- goto err_free_bus;
- }
-
- dsi->dphy = dphy;
-
- return 0;
-
-err_free_bus:
- regmap_mmio_detach_clk(dphy->regs);
- clk_put(dphy->bus_clk);
-err_free_reset:
- reset_control_put(dphy->reset);
- return ret;
-}
-
-int sun6i_dphy_remove(struct sun6i_dsi *dsi)
-{
- struct sun6i_dphy *dphy = dsi->dphy;
-
- regmap_mmio_detach_clk(dphy->regs);
- clk_put(dphy->mod_clk);
- clk_put(dphy->bus_clk);
- reset_control_put(dphy->reset);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index e3b34a345546..318994cd1b85 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -16,12 +16,13 @@
#include <linux/slab.h>
#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "sun4i_drv.h"
#include "sun6i_mipi_dsi.h"
@@ -616,6 +617,8 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
struct mipi_dsi_device *device = dsi->device;
+ union phy_configure_opts opts = { 0 };
+ struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
u16 delay;
DRM_DEBUG_DRIVER("Enabling DSI output\n");
@@ -634,8 +637,15 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
sun6i_dsi_setup_format(dsi, mode);
sun6i_dsi_setup_timings(dsi, mode);
- sun6i_dphy_init(dsi->dphy, device->lanes);
- sun6i_dphy_power_on(dsi->dphy, device->lanes);
+ phy_init(dsi->dphy);
+
+ phy_mipi_dphy_get_default_config(mode->clock * 1000,
+ mipi_dsi_pixel_format_to_bpp(device->format),
+ device->lanes, cfg);
+
+ phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);
+ phy_configure(dsi->dphy, &opts);
+ phy_power_on(dsi->dphy);
if (!IS_ERR(dsi->panel))
drm_panel_prepare(dsi->panel);
@@ -673,8 +683,8 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
drm_panel_unprepare(dsi->panel);
}
- sun6i_dphy_power_off(dsi->dphy);
- sun6i_dphy_exit(dsi->dphy);
+ phy_power_off(dsi->dphy);
+ phy_exit(dsi->dphy);
pm_runtime_put(dsi->dev);
}
@@ -967,7 +977,6 @@ static const struct component_ops sun6i_dsi_ops = {
static int sun6i_dsi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *dphy_node;
struct sun6i_dsi *dsi;
struct resource *res;
void __iomem *base;
@@ -1013,11 +1022,10 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
*/
clk_set_rate_exclusive(dsi->mod_clk, 297000000);
- dphy_node = of_parse_phandle(dev->of_node, "phys", 0);
- ret = sun6i_dphy_probe(dsi, dphy_node);
- of_node_put(dphy_node);
- if (ret) {
+ dsi->dphy = devm_phy_get(dev, "dphy");
+ if (IS_ERR(dsi->dphy)) {
dev_err(dev, "Couldn't get the MIPI D-PHY\n");
+ ret = PTR_ERR(dsi->dphy);
goto err_unprotect_clk;
}
@@ -1026,7 +1034,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
ret = mipi_dsi_host_register(&dsi->host);
if (ret) {
dev_err(dev, "Couldn't register MIPI-DSI host\n");
- goto err_remove_phy;
+ goto err_pm_disable;
}
ret = component_add(&pdev->dev, &sun6i_dsi_ops);
@@ -1039,9 +1047,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
err_remove_dsi_host:
mipi_dsi_host_unregister(&dsi->host);
-err_remove_phy:
+err_pm_disable:
pm_runtime_disable(dev);
- sun6i_dphy_remove(dsi);
err_unprotect_clk:
clk_rate_exclusive_put(dsi->mod_clk);
return ret;
@@ -1055,7 +1062,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
component_del(&pdev->dev, &sun6i_dsi_ops);
mipi_dsi_host_unregister(&dsi->host);
pm_runtime_disable(dev);
- sun6i_dphy_remove(dsi);
clk_rate_exclusive_put(dsi->mod_clk);
return 0;
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index dbbc5b3ecbda..a07090579f84 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -13,13 +13,6 @@
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
-struct sun6i_dphy {
- struct clk *bus_clk;
- struct clk *mod_clk;
- struct regmap *regs;
- struct reset_control *reset;
-};
-
struct sun6i_dsi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -29,7 +22,7 @@ struct sun6i_dsi {
struct clk *mod_clk;
struct regmap *regs;
struct reset_control *reset;
- struct sun6i_dphy *dphy;
+ struct phy *dphy;
struct device *dev;
struct sun4i_drv *drv;
@@ -52,12 +45,4 @@ static inline struct sun6i_dsi *encoder_to_sun6i_dsi(const struct drm_encoder *e
return container_of(encoder, struct sun6i_dsi, encoder);
};
-int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node);
-int sun6i_dphy_remove(struct sun6i_dsi *dsi);
-
-int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes);
-int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes);
-int sun6i_dphy_power_off(struct sun6i_dphy *dphy);
-int sun6i_dphy_exit(struct sun6i_dphy *dphy);
-
#endif /* _SUN6I_MIPI_DSI_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 44a9ba7d8433..30a2eff55687 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -14,10 +14,10 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <linux/component.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 18534263a05d..a342ec8b131e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -16,11 +16,11 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "sun8i_ui_layer.h"
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 87be898f9b7a..8a0616238467 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -10,11 +10,11 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "sun8i_vi_layer.h"
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index 2e0d6213f6bc..33c463e8d49f 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -10,6 +10,7 @@ tegra-drm-y := \
dc.o \
output.o \
rgb.o \
+ hda.o \
hdmi.o \
mipi-phy.o \
dsi.o \
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 4b70ce664c41..0c5f1e6a0446 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -92,10 +92,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
return -ENOMEM;
if (iommu_present(&platform_bus_type)) {
- u64 carveout_start, carveout_end, gem_start, gem_end;
- struct iommu_domain_geometry *geometry;
- unsigned long order;
-
tegra->domain = iommu_domain_alloc(&platform_bus_type);
if (!tegra->domain) {
err = -ENOMEM;
@@ -105,27 +101,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
err = iova_cache_get();
if (err < 0)
goto domain;
-
- geometry = &tegra->domain->geometry;
- gem_start = geometry->aperture_start;
- gem_end = geometry->aperture_end - CARVEOUT_SZ;
- carveout_start = gem_end + 1;
- carveout_end = geometry->aperture_end;
-
- order = __ffs(tegra->domain->pgsize_bitmap);
- init_iova_domain(&tegra->carveout.domain, 1UL << order,
- carveout_start >> order);
-
- tegra->carveout.shift = iova_shift(&tegra->carveout.domain);
- tegra->carveout.limit = carveout_end >> tegra->carveout.shift;
-
- drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1);
- mutex_init(&tegra->mm_lock);
-
- DRM_DEBUG("IOMMU apertures:\n");
- DRM_DEBUG(" GEM: %#llx-%#llx\n", gem_start, gem_end);
- DRM_DEBUG(" Carveout: %#llx-%#llx\n", carveout_start,
- carveout_end);
}
mutex_init(&tegra->clients_lock);
@@ -159,6 +134,36 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (err < 0)
goto fbdev;
+ if (tegra->domain) {
+ u64 carveout_start, carveout_end, gem_start, gem_end;
+ u64 dma_mask = dma_get_mask(&device->dev);
+ dma_addr_t start, end;
+ unsigned long order;
+
+ start = tegra->domain->geometry.aperture_start & dma_mask;
+ end = tegra->domain->geometry.aperture_end & dma_mask;
+
+ gem_start = start;
+ gem_end = end - CARVEOUT_SZ;
+ carveout_start = gem_end + 1;
+ carveout_end = end;
+
+ order = __ffs(tegra->domain->pgsize_bitmap);
+ init_iova_domain(&tegra->carveout.domain, 1UL << order,
+ carveout_start >> order);
+
+ tegra->carveout.shift = iova_shift(&tegra->carveout.domain);
+ tegra->carveout.limit = carveout_end >> tegra->carveout.shift;
+
+ drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1);
+ mutex_init(&tegra->mm_lock);
+
+ DRM_DEBUG("IOMMU apertures:\n");
+ DRM_DEBUG(" GEM: %#llx-%#llx\n", gem_start, gem_end);
+ DRM_DEBUG(" Carveout: %#llx-%#llx\n", carveout_start,
+ carveout_end);
+ }
+
if (tegra->hub) {
err = tegra_display_hub_prepare(tegra->hub);
if (err < 0)
@@ -1041,6 +1046,7 @@ int tegra_drm_register_client(struct tegra_drm *tegra,
{
mutex_lock(&tegra->clients_lock);
list_add_tail(&client->list, &tegra->clients);
+ client->drm = tegra;
mutex_unlock(&tegra->clients_lock);
return 0;
@@ -1051,6 +1057,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
{
mutex_lock(&tegra->clients_lock);
list_del_init(&client->list);
+ client->drm = NULL;
mutex_unlock(&tegra->clients_lock);
return 0;
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 1012335bb489..70154c253d45 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -17,11 +17,11 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fixed.h>
+#include <drm/drm_probe_helper.h>
#include "gem.h"
#include "hub.h"
@@ -88,6 +88,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
struct tegra_drm_client {
struct host1x_client base;
struct list_head list;
+ struct tegra_drm *drm;
unsigned int version;
const struct tegra_drm_client_ops *ops;
@@ -124,7 +125,7 @@ struct tegra_output {
struct drm_panel *panel;
struct i2c_adapter *ddc;
const struct edid *edid;
- struct cec_notifier *notifier;
+ struct cec_notifier *cec;
unsigned int hpd_irq;
int hpd_gpio;
enum of_gpio_flags hpd_gpio_flags;
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index b947e82bbeb1..0a4ce05e00ab 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -15,6 +15,7 @@
#include "drm.h"
#include "gem.h"
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
#ifdef CONFIG_DRM_FBDEV_EMULATION
static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper)
@@ -255,7 +256,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
helper->fbdev = info;
info->par = helper;
- info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &tegra_fb_ops;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
diff --git a/drivers/gpu/drm/tegra/hda.c b/drivers/gpu/drm/tegra/hda.c
new file mode 100644
index 000000000000..94245a18a043
--- /dev/null
+++ b/drivers/gpu/drm/tegra/hda.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2019 NVIDIA Corporation
+ */
+
+#include <linux/bug.h>
+
+#include <sound/hda_verbs.h>
+
+#include "hda.h"
+
+void tegra_hda_parse_format(unsigned int format, struct tegra_hda_format *fmt)
+{
+ unsigned int mul, div, bits, channels;
+
+ if (format & AC_FMT_TYPE_NON_PCM)
+ fmt->pcm = false;
+ else
+ fmt->pcm = true;
+
+ if (format & AC_FMT_BASE_44K)
+ fmt->sample_rate = 44100;
+ else
+ fmt->sample_rate = 48000;
+
+ mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT;
+ div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT;
+
+ fmt->sample_rate *= (mul + 1) / (div + 1);
+
+ switch (format & AC_FMT_BITS_MASK) {
+ case AC_FMT_BITS_8:
+ fmt->bits = 8;
+ break;
+
+ case AC_FMT_BITS_16:
+ fmt->bits = 16;
+ break;
+
+ case AC_FMT_BITS_20:
+ fmt->bits = 20;
+ break;
+
+ case AC_FMT_BITS_24:
+ fmt->bits = 24;
+ break;
+
+ case AC_FMT_BITS_32:
+ fmt->bits = 32;
+ break;
+
+ default:
+ bits = (format & AC_FMT_BITS_MASK) >> AC_FMT_BITS_SHIFT;
+ WARN(1, "invalid number of bits: %#x\n", bits);
+ fmt->bits = 8;
+ break;
+ }
+
+ channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT;
+
+ /* channels are encoded as n - 1 */
+ fmt->channels = channels + 1;
+}
diff --git a/drivers/gpu/drm/tegra/hda.h b/drivers/gpu/drm/tegra/hda.h
new file mode 100644
index 000000000000..77269955a4f2
--- /dev/null
+++ b/drivers/gpu/drm/tegra/hda.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2019 NVIDIA Corporation
+ */
+
+#ifndef DRM_TEGRA_HDA_H
+#define DRM_TEGRA_HDA_H 1
+
+#include <linux/types.h>
+
+struct tegra_hda_format {
+ unsigned int sample_rate;
+ unsigned int channels;
+ unsigned int bits;
+ bool pcm;
+};
+
+void tegra_hda_parse_format(unsigned int format, struct tegra_hda_format *fmt);
+
+#endif
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index a7566c67bfb0..47c55974756d 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -11,6 +11,7 @@
#include <linux/debugfs.h>
#include <linux/gpio.h>
#include <linux/hdmi.h>
+#include <linux/math64.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -18,12 +19,9 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include <sound/hda_verbs.h>
-
-#include <media/cec-notifier.h>
+#include <drm/drm_probe_helper.h>
+#include "hda.h"
#include "hdmi.h"
#include "drm.h"
#include "dc.h"
@@ -71,8 +69,7 @@ struct tegra_hdmi {
const struct tegra_hdmi_config *config;
unsigned int audio_source;
- unsigned int audio_sample_rate;
- unsigned int audio_channels;
+ struct tegra_hda_format format;
unsigned int pixel_clock;
bool stereo;
@@ -119,68 +116,11 @@ static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, u32 value,
}
struct tegra_hdmi_audio_config {
- unsigned int pclk;
unsigned int n;
unsigned int cts;
unsigned int aval;
};
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = {
- { 25200000, 4096, 25200, 24000 },
- { 27000000, 4096, 27000, 24000 },
- { 74250000, 4096, 74250, 24000 },
- { 148500000, 4096, 148500, 24000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = {
- { 25200000, 5880, 26250, 25000 },
- { 27000000, 5880, 28125, 25000 },
- { 74250000, 4704, 61875, 20000 },
- { 148500000, 4704, 123750, 20000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = {
- { 25200000, 6144, 25200, 24000 },
- { 27000000, 6144, 27000, 24000 },
- { 74250000, 6144, 74250, 24000 },
- { 148500000, 6144, 148500, 24000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = {
- { 25200000, 11760, 26250, 25000 },
- { 27000000, 11760, 28125, 25000 },
- { 74250000, 9408, 61875, 20000 },
- { 148500000, 9408, 123750, 20000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = {
- { 25200000, 12288, 25200, 24000 },
- { 27000000, 12288, 27000, 24000 },
- { 74250000, 12288, 74250, 24000 },
- { 148500000, 12288, 148500, 24000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = {
- { 25200000, 23520, 26250, 25000 },
- { 27000000, 23520, 28125, 25000 },
- { 74250000, 18816, 61875, 20000 },
- { 148500000, 18816, 123750, 20000 },
- { 0, 0, 0, 0 },
-};
-
-static const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = {
- { 25200000, 24576, 25200, 24000 },
- { 27000000, 24576, 27000, 24000 },
- { 74250000, 24576, 74250, 24000 },
- { 148500000, 24576, 148500, 24000 },
- { 0, 0, 0, 0 },
-};
-
static const struct tmds_config tegra20_tmds_config[] = {
{ /* slow pixel clock modes */
.pclk = 27000000,
@@ -418,52 +358,53 @@ static const struct tmds_config tegra124_tmds_config[] = {
},
};
-static const struct tegra_hdmi_audio_config *
-tegra_hdmi_get_audio_config(unsigned int sample_rate, unsigned int pclk)
+static int
+tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pix_clock,
+ struct tegra_hdmi_audio_config *config)
{
- const struct tegra_hdmi_audio_config *table;
-
- switch (sample_rate) {
- case 32000:
- table = tegra_hdmi_audio_32k;
- break;
-
- case 44100:
- table = tegra_hdmi_audio_44_1k;
- break;
-
- case 48000:
- table = tegra_hdmi_audio_48k;
- break;
-
- case 88200:
- table = tegra_hdmi_audio_88_2k;
- break;
-
- case 96000:
- table = tegra_hdmi_audio_96k;
- break;
-
- case 176400:
- table = tegra_hdmi_audio_176_4k;
- break;
-
- case 192000:
- table = tegra_hdmi_audio_192k;
- break;
-
- default:
- return NULL;
- }
-
- while (table->pclk) {
- if (table->pclk == pclk)
- return table;
-
- table++;
+ const unsigned int afreq = 128 * audio_freq;
+ const unsigned int min_n = afreq / 1500;
+ const unsigned int max_n = afreq / 300;
+ const unsigned int ideal_n = afreq / 1000;
+ int64_t min_err = (uint64_t)-1 >> 1;
+ unsigned int min_delta = -1;
+ int n;
+
+ memset(config, 0, sizeof(*config));
+ config->n = -1;
+
+ for (n = min_n; n <= max_n; n++) {
+ uint64_t cts_f, aval_f;
+ unsigned int delta;
+ int64_t cts, err;
+
+ /* compute aval in 48.16 fixed point */
+ aval_f = ((int64_t)24000000 << 16) * n;
+ do_div(aval_f, afreq);
+ /* It should round without any rest */
+ if (aval_f & 0xFFFF)
+ continue;
+
+ /* Compute cts in 48.16 fixed point */
+ cts_f = ((int64_t)pix_clock << 16) * n;
+ do_div(cts_f, afreq);
+ /* Round it to the nearest integer */
+ cts = (cts_f & ~0xFFFF) + ((cts_f & BIT(15)) << 1);
+
+ delta = abs(n - ideal_n);
+
+ /* Compute the absolute error */
+ err = abs((int64_t)cts_f - cts);
+ if (err < min_err || (err == min_err && delta < min_delta)) {
+ config->n = n;
+ config->cts = cts >> 16;
+ config->aval = aval_f >> 16;
+ min_delta = delta;
+ min_err = err;
+ }
}
- return NULL;
+ return config->n != -1 ? 0 : -EINVAL;
}
static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi)
@@ -510,7 +451,7 @@ static void tegra_hdmi_write_aval(struct tegra_hdmi *hdmi, u32 value)
unsigned int i;
for (i = 0; i < ARRAY_SIZE(regs); i++) {
- if (regs[i].sample_rate == hdmi->audio_sample_rate) {
+ if (regs[i].sample_rate == hdmi->format.sample_rate) {
tegra_hdmi_writel(hdmi, value, regs[i].offset);
break;
}
@@ -519,8 +460,9 @@ static void tegra_hdmi_write_aval(struct tegra_hdmi *hdmi, u32 value)
static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi)
{
- const struct tegra_hdmi_audio_config *config;
+ struct tegra_hdmi_audio_config config;
u32 source, value;
+ int err;
switch (hdmi->audio_source) {
case HDA:
@@ -564,7 +506,7 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi)
* play back system startup sounds early. It is possibly not
* needed on Linux at all.
*/
- if (hdmi->audio_channels == 2)
+ if (hdmi->format.channels == 2)
value = SOR_AUDIO_CNTRL0_INJECT_NULLSMPL;
else
value = 0;
@@ -595,25 +537,28 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi)
tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_SPARE0);
}
- config = tegra_hdmi_get_audio_config(hdmi->audio_sample_rate,
- hdmi->pixel_clock);
- if (!config) {
+ err = tegra_hdmi_get_audio_config(hdmi->format.sample_rate,
+ hdmi->pixel_clock, &config);
+ if (err < 0) {
dev_err(hdmi->dev,
"cannot set audio to %u Hz at %u Hz pixel clock\n",
- hdmi->audio_sample_rate, hdmi->pixel_clock);
- return -EINVAL;
+ hdmi->format.sample_rate, hdmi->pixel_clock);
+ return err;
}
+ dev_dbg(hdmi->dev, "audio: pixclk=%u, n=%u, cts=%u, aval=%u\n",
+ hdmi->pixel_clock, config.n, config.cts, config.aval);
+
tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL);
value = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE |
- AUDIO_N_VALUE(config->n - 1);
+ AUDIO_N_VALUE(config.n - 1);
tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N);
- tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE,
+ tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config.n) | ACR_ENABLE,
HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH);
- tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config->cts),
+ tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config.cts),
HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW);
value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1);
@@ -624,7 +569,7 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi)
tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N);
if (hdmi->config->has_hda)
- tegra_hdmi_write_aval(hdmi, config->aval);
+ tegra_hdmi_write_aval(hdmi, config.aval);
tegra_hdmi_setup_audio_fs_tables(hdmi);
@@ -788,7 +733,7 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi)
return;
}
- frame.channels = hdmi->audio_channels;
+ frame.channels = hdmi->format.channels;
err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
@@ -1590,24 +1535,6 @@ static const struct of_device_id tegra_hdmi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match);
-static void hda_format_parse(unsigned int format, unsigned int *rate,
- unsigned int *channels)
-{
- unsigned int mul, div;
-
- if (format & AC_FMT_BASE_44K)
- *rate = 44100;
- else
- *rate = 48000;
-
- mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT;
- div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT;
-
- *rate = *rate * (mul + 1) / (div + 1);
-
- *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT;
-}
-
static irqreturn_t tegra_hdmi_irq(int irq, void *data)
{
struct tegra_hdmi *hdmi = data;
@@ -1624,14 +1551,9 @@ static irqreturn_t tegra_hdmi_irq(int irq, void *data)
value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0);
if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) {
- unsigned int sample_rate, channels;
-
format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK;
- hda_format_parse(format, &sample_rate, &channels);
-
- hdmi->audio_sample_rate = sample_rate;
- hdmi->audio_channels = channels;
+ tegra_hda_parse_format(format, &hdmi->format);
err = tegra_hdmi_setup_audio(hdmi);
if (err < 0) {
@@ -1665,8 +1587,6 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
hdmi->dev = &pdev->dev;
hdmi->audio_source = AUTO;
- hdmi->audio_sample_rate = 48000;
- hdmi->audio_channels = 2;
hdmi->stereo = false;
hdmi->dvi = false;
@@ -1710,10 +1630,6 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
return PTR_ERR(hdmi->vdd);
}
- hdmi->output.notifier = cec_notifier_get(&pdev->dev);
- if (hdmi->output.notifier == NULL)
- return -ENOMEM;
-
hdmi->output.dev = &pdev->dev;
err = tegra_output_probe(&hdmi->output);
@@ -1772,9 +1688,6 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
tegra_output_remove(&hdmi->output);
- if (hdmi->output.notifier)
- cec_notifier_put(hdmi->output.notifier);
-
return 0;
}
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
index 71cc3cf60066..ba9b3cfb8c3d 100644
--- a/drivers/gpu/drm/tegra/hub.c
+++ b/drivers/gpu/drm/tegra/hub.c
@@ -19,7 +19,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "drm.h"
#include "dc.h"
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index c662efc7e413..9c2b9dad55c3 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -36,7 +36,7 @@ int tegra_output_connector_get_modes(struct drm_connector *connector)
else if (output->ddc)
edid = drm_get_edid(connector, output->ddc);
- cec_notifier_set_phys_addr_from_edid(output->notifier, edid);
+ cec_notifier_set_phys_addr_from_edid(output->cec, edid);
drm_connector_update_edid_property(connector, edid);
if (edid) {
@@ -73,7 +73,7 @@ tegra_output_connector_detect(struct drm_connector *connector, bool force)
}
if (status != connector_status_connected)
- cec_notifier_phys_addr_invalidate(output->notifier);
+ cec_notifier_phys_addr_invalidate(output->cec);
return status;
}
@@ -174,11 +174,18 @@ int tegra_output_probe(struct tegra_output *output)
disable_irq(output->hpd_irq);
}
+ output->cec = cec_notifier_get(output->dev);
+ if (!output->cec)
+ return -ENOMEM;
+
return 0;
}
void tegra_output_remove(struct tegra_output *output)
{
+ if (output->cec)
+ cec_notifier_put(output->cec);
+
if (gpio_is_valid(output->hpd_gpio)) {
free_irq(output->hpd_irq, output);
gpio_free(output->hpd_gpio);
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 44feac2a0359..40057106f5f3 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -19,8 +19,6 @@
#include <soc/tegra/pmc.h>
-#include <sound/hda_verbs.h>
-
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
@@ -28,6 +26,7 @@
#include "dc.h"
#include "drm.h"
+#include "hda.h"
#include "sor.h"
#include "trace.h"
@@ -411,6 +410,8 @@ struct tegra_sor {
struct clk *clk_dp;
struct clk *clk;
+ u8 xbar_cfg[5];
+
struct drm_dp_aux *aux;
struct drm_info_list *debugfs_files;
@@ -429,10 +430,7 @@ struct tegra_sor {
struct delayed_work scdc;
bool scdc_enabled;
- struct {
- unsigned int sample_rate;
- unsigned int channels;
- } audio;
+ struct tegra_hda_format format;
};
struct tegra_sor_state {
@@ -1818,7 +1816,7 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
/* XXX not in TRM */
for (value = 0, i = 0; i < 5; i++)
- value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) |
+ value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->xbar_cfg[i]) |
SOR_XBAR_CTRL_LINK1_XSEL(i, i);
tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL);
@@ -2186,7 +2184,7 @@ static int tegra_sor_hdmi_enable_audio_infoframe(struct tegra_sor *sor)
return err;
}
- frame.channels = sor->audio.channels;
+ frame.channels = sor->format.channels;
err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
@@ -2215,7 +2213,7 @@ static void tegra_sor_hdmi_audio_enable(struct tegra_sor *sor)
value |= SOR_AUDIO_CNTRL_SOURCE_SELECT(SOURCE_SELECT_HDA);
/* inject null samples */
- if (sor->audio.channels != 2)
+ if (sor->format.channels != 2)
value &= ~SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
else
value |= SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
@@ -2246,7 +2244,7 @@ static void tegra_sor_hdmi_audio_enable(struct tegra_sor *sor)
value = SOR_HDMI_AUDIO_N_RESET | SOR_HDMI_AUDIO_N_LOOKUP;
tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_N);
- value = (24000 * 4096) / (128 * sor->audio.sample_rate / 1000);
+ value = (24000 * 4096) / (128 * sor->format.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0320);
tegra_sor_writel(sor, 4096, SOR_AUDIO_NVAL_0320);
@@ -2259,15 +2257,15 @@ static void tegra_sor_hdmi_audio_enable(struct tegra_sor *sor)
tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_1764);
tegra_sor_writel(sor, 18816, SOR_AUDIO_NVAL_1764);
- value = (24000 * 6144) / (128 * sor->audio.sample_rate / 1000);
+ value = (24000 * 6144) / (128 * sor->format.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0480);
tegra_sor_writel(sor, 6144, SOR_AUDIO_NVAL_0480);
- value = (24000 * 12288) / (128 * sor->audio.sample_rate / 1000);
+ value = (24000 * 12288) / (128 * sor->format.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0960);
tegra_sor_writel(sor, 12288, SOR_AUDIO_NVAL_0960);
- value = (24000 * 24576) / (128 * sor->audio.sample_rate / 1000);
+ value = (24000 * 24576) / (128 * sor->format.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_1920);
tegra_sor_writel(sor, 24576, SOR_AUDIO_NVAL_1920);
@@ -2555,7 +2553,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
/* XXX not in TRM */
for (value = 0, i = 0; i < 5; i++)
- value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) |
+ value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->xbar_cfg[i]) |
SOR_XBAR_CTRL_LINK1_XSEL(i, i);
tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL);
@@ -3176,6 +3174,8 @@ MODULE_DEVICE_TABLE(of, tegra_sor_of_match);
static int tegra_sor_parse_dt(struct tegra_sor *sor)
{
struct device_node *np = sor->dev->of_node;
+ u32 xbar_cfg[5];
+ unsigned int i;
u32 value;
int err;
@@ -3193,25 +3193,18 @@ static int tegra_sor_parse_dt(struct tegra_sor *sor)
sor->pad = TEGRA_IO_PAD_HDMI_DP0 + sor->index;
}
- return 0;
-}
-
-static void tegra_hda_parse_format(unsigned int format, unsigned int *rate,
- unsigned int *channels)
-{
- unsigned int mul, div;
-
- if (format & AC_FMT_BASE_44K)
- *rate = 44100;
- else
- *rate = 48000;
-
- mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT;
- div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT;
-
- *rate = *rate * (mul + 1) / (div + 1);
+ err = of_property_read_u32_array(np, "nvidia,xbar-cfg", xbar_cfg, 5);
+ if (err < 0) {
+ /* fall back to default per-SoC XBAR configuration */
+ for (i = 0; i < 5; i++)
+ sor->xbar_cfg[i] = sor->soc->xbar_cfg[i];
+ } else {
+ /* copy cells to SOR XBAR configuration */
+ for (i = 0; i < 5; i++)
+ sor->xbar_cfg[i] = xbar_cfg[i];
+ }
- *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT;
+ return 0;
}
static irqreturn_t tegra_sor_irq(int irq, void *data)
@@ -3226,14 +3219,11 @@ static irqreturn_t tegra_sor_irq(int irq, void *data)
value = tegra_sor_readl(sor, SOR_AUDIO_HDA_CODEC_SCRATCH0);
if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) {
- unsigned int format, sample_rate, channels;
+ unsigned int format;
format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK;
- tegra_hda_parse_format(format, &sample_rate, &channels);
-
- sor->audio.sample_rate = sample_rate;
- sor->audio.channels = channels;
+ tegra_hda_parse_format(format, &sor->format);
tegra_sor_hdmi_audio_enable(sor);
} else {
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index d47983deb1cf..39bfed9623de 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -26,6 +26,7 @@
struct vic_config {
const char *firmware;
unsigned int version;
+ bool supports_sid;
};
struct vic {
@@ -105,6 +106,22 @@ static int vic_boot(struct vic *vic)
if (vic->booted)
return 0;
+ if (vic->config->supports_sid) {
+ struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
+ u32 value;
+
+ value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
+ TRANSCFG_ATT(0, TRANSCFG_SID_HW);
+ vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
+
+ if (spec && spec->num_ids > 0) {
+ value = spec->ids[0] & 0xffff;
+
+ vic_writel(vic, value, VIC_THI_STREAMID0);
+ vic_writel(vic, value, VIC_THI_STREAMID1);
+ }
+ }
+
/* setup clockgating registers */
vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
CG_IDLE_CG_EN |
@@ -181,13 +198,6 @@ static int vic_init(struct host1x_client *client)
vic->domain = tegra->domain;
}
- if (!vic->falcon.data) {
- vic->falcon.data = tegra;
- err = falcon_load_firmware(&vic->falcon);
- if (err < 0)
- goto detach;
- }
-
vic->channel = host1x_channel_request(client->dev);
if (!vic->channel) {
err = -ENOMEM;
@@ -246,6 +256,30 @@ static const struct host1x_client_ops vic_client_ops = {
.exit = vic_exit,
};
+static int vic_load_firmware(struct vic *vic)
+{
+ int err;
+
+ if (vic->falcon.data)
+ return 0;
+
+ vic->falcon.data = vic->client.drm;
+
+ err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
+ if (err < 0)
+ goto cleanup;
+
+ err = falcon_load_firmware(&vic->falcon);
+ if (err < 0)
+ goto cleanup;
+
+ return 0;
+
+cleanup:
+ vic->falcon.data = NULL;
+ return err;
+}
+
static int vic_open_channel(struct tegra_drm_client *client,
struct tegra_drm_context *context)
{
@@ -256,19 +290,25 @@ static int vic_open_channel(struct tegra_drm_client *client,
if (err < 0)
return err;
+ err = vic_load_firmware(vic);
+ if (err < 0)
+ goto rpm_put;
+
err = vic_boot(vic);
- if (err < 0) {
- pm_runtime_put(vic->dev);
- return err;
- }
+ if (err < 0)
+ goto rpm_put;
context->channel = host1x_channel_get(vic->channel);
if (!context->channel) {
- pm_runtime_put(vic->dev);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto rpm_put;
}
return 0;
+
+rpm_put:
+ pm_runtime_put(vic->dev);
+ return err;
}
static void vic_close_channel(struct tegra_drm_context *context)
@@ -291,6 +331,7 @@ static const struct tegra_drm_client_ops vic_ops = {
static const struct vic_config vic_t124_config = {
.firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE,
.version = 0x40,
+ .supports_sid = false,
};
#define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin"
@@ -298,6 +339,7 @@ static const struct vic_config vic_t124_config = {
static const struct vic_config vic_t210_config = {
.firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
.version = 0x21,
+ .supports_sid = false,
};
#define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin"
@@ -305,6 +347,7 @@ static const struct vic_config vic_t210_config = {
static const struct vic_config vic_t186_config = {
.firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
.version = 0x18,
+ .supports_sid = true,
};
#define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
@@ -312,6 +355,7 @@ static const struct vic_config vic_t186_config = {
static const struct vic_config vic_t194_config = {
.firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
.version = 0x19,
+ .supports_sid = true,
};
static const struct of_device_id vic_match[] = {
@@ -372,10 +416,6 @@ static int vic_probe(struct platform_device *pdev)
if (err < 0)
return err;
- err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
- if (err < 0)
- goto exit_falcon;
-
platform_set_drvdata(pdev, vic);
INIT_LIST_HEAD(&vic->client.base.list);
@@ -393,7 +433,6 @@ static int vic_probe(struct platform_device *pdev)
err = host1x_client_register(&vic->client.base);
if (err < 0) {
dev_err(dev, "failed to register host1x client: %d\n", err);
- platform_set_drvdata(pdev, NULL);
goto exit_falcon;
}
diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h
index 21844817a7e1..017584340dd6 100644
--- a/drivers/gpu/drm/tegra/vic.h
+++ b/drivers/gpu/drm/tegra/vic.h
@@ -17,11 +17,20 @@
/* VIC registers */
+#define VIC_THI_STREAMID0 0x00000030
+#define VIC_THI_STREAMID1 0x00000034
+
#define NV_PVIC_MISC_PRI_VIC_CG 0x000016d0
#define CG_IDLE_CG_DLY_CNT(val) ((val & 0x3f) << 0)
#define CG_IDLE_CG_EN (1 << 6)
#define CG_WAKEUP_DLY_CNT(val) ((val & 0xf) << 16)
+#define VIC_TFBIF_TRANSCFG 0x00002044
+#define TRANSCFG_ATT(i, v) (((v) & 0x3) << (i * 4))
+#define TRANSCFG_SID_HW 0
+#define TRANSCFG_SID_PHY 1
+#define TRANSCFG_SID_FALCON 2
+
/* Firmware offsets */
#define VIC_UCODE_FCE_HEADER_OFFSET (6*4)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 337e86a1d5ea..3030af9e7b35 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -24,6 +24,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "tilcdc_drv.h"
#include "tilcdc_regs.h"
@@ -511,7 +512,7 @@ static int tilcdc_debugfs_init(struct drm_minor *minor)
DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver tilcdc_driver = {
- .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
+ .driver_features = (DRIVER_GEM | DRIVER_MODESET |
DRIVER_PRIME | DRIVER_ATOMIC),
.irq_handler = tilcdc_irq,
.gem_free_object_unlocked = drm_gem_cma_free_object,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 62cea5ff5558..d86397da12a9 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -30,10 +30,9 @@
#include <linux/list.h>
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
/* Defaulting to pixel clock defined on AM335x */
#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index b4eaf9bc87f8..e9969cd36610 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -10,6 +10,7 @@
#include <linux/component.h>
#include <linux/of_graph.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_of.h>
#include "tilcdc_drv.h"
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index a1acab39d87f..5d532a596e1e 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -23,6 +23,7 @@
#include <video/of_display_timing.h>
#include <video/videomode.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "tilcdc_drv.h"
#include "tilcdc_panel.h"
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index daebf1aa6b0a..fe59fbfdde69 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -21,6 +21,7 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "tilcdc_drv.h"
#include "tilcdc_tfp410.h"
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 614f532ea89f..554abd5d3b53 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -9,10 +9,10 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_print.h>
#include <drm/tinydrm/tinydrm.h>
#include <linux/device.h>
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
index 323564329535..bb5b1c1e21ba 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
@@ -8,10 +8,10 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modes.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_print.h>
#include <drm/tinydrm/tinydrm.h>
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 0ec08394e17a..3f56647cdb35 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -198,19 +198,22 @@ static void ttm_bo_ref_bug(struct kref *list_kref)
void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
{
+ struct ttm_bo_device *bdev = bo->bdev;
+ bool notify = false;
+
if (!list_empty(&bo->swap)) {
list_del_init(&bo->swap);
kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ notify = true;
}
if (!list_empty(&bo->lru)) {
list_del_init(&bo->lru);
kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ notify = true;
}
- /*
- * TODO: Add a driver hook to delete from
- * driver-specific LRU's here.
- */
+ if (notify && bdev->driver->del_from_lru_notify)
+ bdev->driver->del_from_lru_notify(bo);
}
void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo)
@@ -676,15 +679,6 @@ void ttm_bo_put(struct ttm_buffer_object *bo)
}
EXPORT_SYMBOL(ttm_bo_put);
-void ttm_bo_unref(struct ttm_buffer_object **p_bo)
-{
- struct ttm_buffer_object *bo = *p_bo;
-
- *p_bo = NULL;
- ttm_bo_put(bo);
-}
-EXPORT_SYMBOL(ttm_bo_unref);
-
int ttm_bo_lock_delayed_workqueue(struct ttm_bo_device *bdev)
{
return cancel_delayed_work_sync(&bdev->wq);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index a1d977fbade5..e86a29a1e51f 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -71,7 +71,7 @@ static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
ttm_bo_get(bo);
up_read(&vmf->vma->vm_mm->mmap_sem);
(void) dma_fence_wait(bo->moving, true);
- ttm_bo_unreserve(bo);
+ reservation_object_unlock(bo->resv);
ttm_bo_put(bo);
goto out_unlock;
}
@@ -131,11 +131,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
* for reserve, and if it fails, retry the fault after waiting
* for the buffer to become unreserved.
*/
- err = ttm_bo_reserve(bo, true, true, NULL);
- if (unlikely(err != 0)) {
- if (err != -EBUSY)
- return VM_FAULT_NOPAGE;
-
+ if (unlikely(!reservation_object_trylock(bo->resv))) {
if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) {
if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
ttm_bo_get(bo);
@@ -165,6 +161,8 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
}
if (bdev->driver->fault_reserve_notify) {
+ struct dma_fence *moving = dma_fence_get(bo->moving);
+
err = bdev->driver->fault_reserve_notify(bo);
switch (err) {
case 0:
@@ -177,6 +175,13 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
ret = VM_FAULT_SIGBUS;
goto out_unlock;
}
+
+ if (bo->moving != moving) {
+ spin_lock(&bdev->glob->lru_lock);
+ ttm_bo_move_to_lru_tail(bo, NULL);
+ spin_unlock(&bdev->glob->lru_lock);
+ }
+ dma_fence_put(moving);
}
/*
@@ -291,7 +296,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
out_io_unlock:
ttm_mem_io_unlock(man);
out_unlock:
- ttm_bo_unreserve(bo);
+ reservation_object_unlock(bo->resv);
return ret;
}
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 28e2d03c0ccf..d5c6a7ecf232 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -43,14 +43,14 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_panel.h>
#include <drm/drm_of.h>
-#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include "tve200_drm.h"
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index 68e88bed77ca..66885c24590f 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -14,6 +14,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "udl_connector.h"
#include "udl_drv.h"
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index a63e3011e971..22cd2d13e272 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "udl_drv.h"
static int udl_usb_suspend(struct usb_interface *interface,
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 1b014d92855b..9086d0d1b880 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -12,6 +12,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include "udl_drv.h"
/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index f7508e907536..4704b2df3688 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -234,18 +234,21 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
for (q = 0; q < V3D_MAX_QUEUES; q++) {
struct drm_gpu_scheduler *sched = &v3d->queue[q].sched;
- kthread_park(sched->thread);
- drm_sched_hw_job_reset(sched, (sched_job->sched == sched ?
- sched_job : NULL));
+ drm_sched_stop(sched);
+
+ if(sched_job)
+ drm_sched_increase_karma(sched_job);
}
/* get the GPU back into the init state */
v3d_reset(v3d);
+ for (q = 0; q < V3D_MAX_QUEUES; q++)
+ drm_sched_resubmit_jobs(sched_job->sched);
+
/* Unblock schedulers and restart their jobs. */
for (q = 0; q < V3D_MAX_QUEUES; q++) {
- drm_sched_job_recovery(&v3d->queue[q].sched);
- kthread_unpark(v3d->queue[q].sched.thread);
+ drm_sched_start(&v3d->queue[q].sched, true);
}
mutex_unlock(&v3d->reset_lock);
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 97caf1671dd0..730008d3da76 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -34,8 +34,8 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <drm/drm_fb_cma_helper.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index f185812970da..169521e547ba 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -24,10 +24,10 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_graph.h>
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index f6f5cd80c04d..5fcd2f0da7f7 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -175,7 +175,6 @@ static struct drm_driver vc4_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM |
- DRIVER_HAVE_IRQ |
DRIVER_RENDER |
DRIVER_PRIME |
DRIVER_SYNCOBJ),
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 0c607eb33d7e..11702e1d9011 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -30,11 +30,11 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/completion.h>
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 051b61b62541..88fd5df7e7dc 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -43,8 +43,8 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/i2c.h>
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 0490edb192a1..91b8c72ff361 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -17,9 +17,9 @@
#include <drm/drm_crtc.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include "vc4_drv.h"
#include "vc4_regs.h"
diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c
index 437e7a27f21d..495150415020 100644
--- a/drivers/gpu/drm/vc4/vc4_perfmon.c
+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
@@ -117,7 +117,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- perfmon = kzalloc(sizeof(*perfmon) + (req->ncounters * sizeof(u64)),
+ perfmon = kzalloc(struct_size(perfmon, counters, req->ncounters),
GFP_KERNEL);
if (!perfmon)
return -ENOMEM;
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index 6e23c50168f9..aa279b5b0de7 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -9,9 +9,9 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_writeback.h>
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 8e7facb6514e..858c3a483229 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -25,9 +25,9 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_graph.h>
diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
index 345bda4494e1..8bf3a7c23ed3 100644
--- a/drivers/gpu/drm/via/via_dmablit.c
+++ b/drivers/gpu/drm/via/via_dmablit.c
@@ -177,12 +177,14 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
switch (vsg->state) {
case dr_via_device_mapped:
via_unmap_blit_from_device(pdev, vsg);
+ /* fall through */
case dr_via_desc_pages_alloc:
for (i = 0; i < vsg->num_desc_pages; ++i) {
if (vsg->desc_pages[i] != NULL)
free_page((unsigned long)vsg->desc_pages[i]);
}
kfree(vsg->desc_pages);
+ /* fall through */
case dr_via_pages_locked:
for (i = 0; i < vsg->num_pages; ++i) {
if (NULL != (page = vsg->pages[i])) {
@@ -191,8 +193,10 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
put_page(page);
}
}
+ /* fall through */
case dr_via_pages_alloc:
vfree(vsg->pages);
+ /* fall through */
default:
vsg->state = dr_via_sg_init;
}
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index aaf766f7cca2..af6a12d3c058 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -70,8 +70,7 @@ static const struct file_operations via_driver_fops = {
static struct drm_driver driver = {
.driver_features =
- DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY |
- DRIVER_IRQ_SHARED,
+ DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY,
.load = via_driver_load,
.unload = via_driver_unload,
.open = via_driver_open,
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 87d7c49cf057..653ec7d0bf4d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -26,9 +26,9 @@
*/
#include "virtgpu_drv.h"
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#define XRES_MIN 32
#define YRES_MIN 32
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index af92964b6889..b996ac1d4fcc 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -205,14 +205,10 @@ static struct drm_driver driver = {
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = virtio_gpu_debugfs_init,
#endif
- .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
- .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = virtgpu_gem_prime_pin,
.gem_prime_unpin = virtgpu_gem_prime_unpin,
- .gem_prime_get_sg_table = virtgpu_gem_prime_get_sg_table,
- .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
.gem_prime_vmap = virtgpu_gem_prime_vmap,
.gem_prime_vunmap = virtgpu_gem_prime_vunmap,
.gem_prime_mmap = virtgpu_gem_prime_mmap,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index cf896d879382..3238fdf58eb4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -34,9 +34,9 @@
#include <drm/drmP.h>
#include <drm/drm_gem.h>
#include <drm/drm_atomic.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
@@ -354,10 +354,6 @@ int virtio_gpu_object_wait(struct virtio_gpu_object *bo, bool no_wait);
/* virtgpu_prime.c */
int virtgpu_gem_prime_pin(struct drm_gem_object *obj);
void virtgpu_gem_prime_unpin(struct drm_gem_object *obj);
-struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
-struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
- struct drm_device *dev, struct dma_buf_attachment *attach,
- struct sg_table *sgt);
void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj);
void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int virtgpu_gem_prime_mmap(struct drm_gem_object *obj,
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index f39a183d59c2..e7e946035027 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -28,10 +28,21 @@
static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
uint32_t *resid)
{
+#if 0
int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
if (handle < 0)
return handle;
+#else
+ static int handle;
+
+ /*
+ * FIXME: dirty hack to avoid re-using IDs, virglrenderer
+ * can't deal with that. Needs fixing in virglrenderer, also
+ * should figure a better way to handle that in the guest.
+ */
+ handle++;
+#endif
*resid = handle + 1;
return 0;
@@ -39,7 +50,9 @@ static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
{
+#if 0
ida_free(&vgdev->resource_ida, id - 1);
+#endif
}
static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c
index 86ce0ae93f59..c59ec34c80a5 100644
--- a/drivers/gpu/drm/virtio/virtgpu_prime.c
+++ b/drivers/gpu/drm/virtio/virtgpu_prime.c
@@ -39,20 +39,6 @@ void virtgpu_gem_prime_unpin(struct drm_gem_object *obj)
WARN_ONCE(1, "not implemented");
}
-struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
-{
- WARN_ONCE(1, "not implemented");
- return ERR_PTR(-ENODEV);
-}
-
-struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
- struct drm_device *dev, struct dma_buf_attachment *attach,
- struct sg_table *table)
-{
- WARN_ONCE(1, "not implemented");
- return ERR_PTR(-ENODEV);
-}
-
void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj)
{
struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
index 9d9e8146db90..d7b409a3c0f8 100644
--- a/drivers/gpu/drm/vkms/vkms_crc.c
+++ b/drivers/gpu/drm/vkms/vkms_crc.c
@@ -1,4 +1,5 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
+
#include "vkms_drv.h"
#include <linux/crc32.h>
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 177bbcb38306..8a9aeb0a9ea8 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -1,22 +1,20 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include "vkms_drv.h"
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
-static void _vblank_handle(struct vkms_output *output)
+static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
{
+ struct vkms_output *output = container_of(timer, struct vkms_output,
+ vblank_hrtimer);
struct drm_crtc *crtc = &output->crtc;
struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
+ u64 ret_overrun;
bool ret;
spin_lock(&output->lock);
+
ret = drm_crtc_handle_vblank(crtc);
if (!ret)
DRM_ERROR("vkms failure on handling vblank");
@@ -37,19 +35,11 @@ static void _vblank_handle(struct vkms_output *output)
DRM_WARN("failed to queue vkms_crc_work_handle");
}
- spin_unlock(&output->lock);
-}
-
-static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
-{
- struct vkms_output *output = container_of(timer, struct vkms_output,
- vblank_hrtimer);
- int ret_overrun;
-
- _vblank_handle(output);
-
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
output->period_ns);
+ WARN_ON(ret_overrun != 1);
+
+ spin_unlock(&output->lock);
return HRTIMER_RESTART;
}
@@ -87,6 +77,9 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
*vblank_time = output->vblank_hrtimer.node.expires;
+ if (!in_vblank_irq)
+ *vblank_time -= output->period_ns;
+
return true;
}
@@ -104,6 +97,7 @@ static void vkms_atomic_crtc_reset(struct drm_crtc *crtc)
vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
if (!vkms_state)
return;
+ INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle);
crtc->state = &vkms_state->base;
crtc->state->crtc = crtc;
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 2a16b86196dc..738dd6206d85 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -1,9 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
/**
* DOC: vkms (Virtual Kernel Modesetting)
@@ -16,10 +11,10 @@
#include <linux/module.h>
#include <drm/drm_gem.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
#include "vkms_drv.h"
#define DRIVER_NAME "vkms"
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index e4469cd3d254..81f1cfbeb936 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
#ifndef _VKMS_DRV_H_
#define _VKMS_DRV_H_
diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c
index 80311daed47a..138b0bb325cf 100644
--- a/drivers/gpu/drm/vkms/vkms_gem.c
+++ b/drivers/gpu/drm/vkms/vkms_gem.c
@@ -1,10 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include <linux/shmem_fs.h>
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 271a0eb9042c..3b162b25312e 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -1,14 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include "vkms_drv.h"
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
static void vkms_connector_destroy(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 418817600ad1..0e67d2d42f0c 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -1,10 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include "vkms_drv.h"
#include <drm/drm_plane_helper.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 7ce1c2f87d9a..5d5c2bce01f3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -534,7 +534,6 @@ static void vmw_user_bo_release(struct ttm_base_object **p_base)
{
struct vmw_user_buffer_object *vmw_user_bo;
struct ttm_base_object *base = *p_base;
- struct ttm_buffer_object *bo;
*p_base = NULL;
@@ -543,8 +542,7 @@ static void vmw_user_bo_release(struct ttm_base_object **p_base)
vmw_user_bo = container_of(base, struct vmw_user_buffer_object,
prime.base);
- bo = &vmw_user_bo->vbo.base;
- ttm_bo_unref(&bo);
+ ttm_bo_put(&vmw_user_bo->vbo.base);
}
@@ -597,7 +595,6 @@ int vmw_user_bo_alloc(struct vmw_private *dev_priv,
struct ttm_base_object **p_base)
{
struct vmw_user_buffer_object *user_bo;
- struct ttm_buffer_object *tmp;
int ret;
user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL);
@@ -614,7 +611,7 @@ int vmw_user_bo_alloc(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
return ret;
- tmp = ttm_bo_reference(&user_bo->vbo.base);
+ ttm_bo_get(&user_bo->vbo.base);
ret = ttm_prime_object_init(tfile,
size,
&user_bo->prime,
@@ -623,7 +620,7 @@ int vmw_user_bo_alloc(struct vmw_private *dev_priv,
&vmw_user_bo_release,
&vmw_user_bo_ref_obj_release);
if (unlikely(ret != 0)) {
- ttm_bo_unref(&tmp);
+ ttm_bo_put(&user_bo->vbo.base);
goto out_no_base_object;
}
@@ -911,7 +908,7 @@ int vmw_user_bo_lookup(struct ttm_object_file *tfile,
vmw_user_bo = container_of(base, struct vmw_user_buffer_object,
prime.base);
- (void)ttm_bo_reference(&vmw_user_bo->vbo.base);
+ ttm_bo_get(&vmw_user_bo->vbo.base);
if (p_base)
*p_base = base;
else
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
index 48d1380a952e..70dab55e7888 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -765,7 +765,7 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man,
if (info->done)
return true;
-
+
memset(info->node, 0, sizeof(*info->node));
spin_lock(&man->lock);
ret = drm_mm_insert_node(&man->mm, info->node, info->page_size);
@@ -1276,8 +1276,10 @@ int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man,
return 0;
out_no_map:
- if (man->using_mob)
- ttm_bo_unref(&man->cmd_space);
+ if (man->using_mob) {
+ ttm_bo_put(man->cmd_space);
+ man->cmd_space = NULL;
+ }
return ret;
}
@@ -1380,7 +1382,8 @@ void vmw_cmdbuf_remove_pool(struct vmw_cmdbuf_man *man)
(void) vmw_cmdbuf_idle(man, false, 10*HZ);
if (man->using_mob) {
(void) ttm_bo_kunmap(&man->map_obj);
- ttm_bo_unref(&man->cmd_space);
+ ttm_bo_put(man->cmd_space);
+ man->cmd_space = NULL;
} else {
dma_free_coherent(&man->dev_priv->dev->pdev->dev,
man->size, man->map, man->handle);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 25afb1d594e3..6165fe2c4504 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -26,6 +26,7 @@
**************************************************************************/
#include <linux/module.h>
#include <linux/console.h>
+#include <linux/dma-mapping.h>
#include <drm/drmP.h>
#include "vmwgfx_drv.h"
@@ -34,7 +35,6 @@
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_module.h>
-#include <linux/intel-iommu.h>
#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
#define VMWGFX_CHIP_SVGAII 0
@@ -546,6 +546,21 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
}
/**
+ * vmw_assume_iommu - Figure out whether coherent dma-remapping might be
+ * taking place.
+ * @dev: Pointer to the struct drm_device.
+ *
+ * Return: true if iommu present, false otherwise.
+ */
+static bool vmw_assume_iommu(struct drm_device *dev)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev->dev);
+
+ return !dma_is_direct(ops) && ops &&
+ ops->map_page != dma_direct_map_page;
+}
+
+/**
* vmw_dma_select_mode - Determine how DMA mappings should be set up for this
* system.
*
@@ -565,55 +580,27 @@ static int vmw_dma_select_mode(struct vmw_private *dev_priv)
[vmw_dma_alloc_coherent] = "Using coherent TTM pages.",
[vmw_dma_map_populate] = "Keeping DMA mappings.",
[vmw_dma_map_bind] = "Giving up DMA mappings early."};
-#ifdef CONFIG_X86
- const struct dma_map_ops *dma_ops = get_dma_ops(dev_priv->dev->dev);
-#ifdef CONFIG_INTEL_IOMMU
- if (intel_iommu_enabled) {
+ if (vmw_force_coherent)
+ dev_priv->map_mode = vmw_dma_alloc_coherent;
+ else if (vmw_assume_iommu(dev_priv->dev))
dev_priv->map_mode = vmw_dma_map_populate;
- goto out_fixup;
- }
-#endif
-
- if (!(vmw_force_iommu || vmw_force_coherent)) {
+ else if (!vmw_force_iommu)
dev_priv->map_mode = vmw_dma_phys;
- DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]);
- return 0;
- }
-
- dev_priv->map_mode = vmw_dma_map_populate;
-
- if (dma_ops && dma_ops->sync_single_for_cpu)
+ else if (IS_ENABLED(CONFIG_SWIOTLB) && swiotlb_nr_tbl())
dev_priv->map_mode = vmw_dma_alloc_coherent;
-#ifdef CONFIG_SWIOTLB
- if (swiotlb_nr_tbl() == 0)
+ else
dev_priv->map_mode = vmw_dma_map_populate;
-#endif
-#ifdef CONFIG_INTEL_IOMMU
-out_fixup:
-#endif
- if (dev_priv->map_mode == vmw_dma_map_populate &&
- vmw_restrict_iommu)
+ if (dev_priv->map_mode == vmw_dma_map_populate && vmw_restrict_iommu)
dev_priv->map_mode = vmw_dma_map_bind;
- if (vmw_force_coherent)
- dev_priv->map_mode = vmw_dma_alloc_coherent;
-
-#if !defined(CONFIG_SWIOTLB) && !defined(CONFIG_INTEL_IOMMU)
- /*
- * No coherent page pool
- */
- if (dev_priv->map_mode == vmw_dma_alloc_coherent)
+ /* No TTM coherent page pool? FIXME: Ask TTM instead! */
+ if (!(IS_ENABLED(CONFIG_SWIOTLB) || IS_ENABLED(CONFIG_INTEL_IOMMU)) &&
+ (dev_priv->map_mode == vmw_dma_alloc_coherent))
return -EINVAL;
-#endif
-
-#else /* CONFIG_X86 */
- dev_priv->map_mode = vmw_dma_map_populate;
-#endif /* CONFIG_X86 */
DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]);
-
return 0;
}
@@ -625,24 +612,20 @@ out_fixup:
* With 32-bit we can only handle 32 bit PFNs. Optionally set that
* restriction also for 64-bit systems.
*/
-#ifdef CONFIG_INTEL_IOMMU
static int vmw_dma_masks(struct vmw_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
+ int ret = 0;
- if (intel_iommu_enabled &&
+ ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64));
+ if (dev_priv->map_mode != vmw_dma_phys &&
(sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) {
DRM_INFO("Restricting DMA addresses to 44 bits.\n");
- return dma_set_mask(dev->dev, DMA_BIT_MASK(44));
+ return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44));
}
- return 0;
-}
-#else
-static int vmw_dma_masks(struct vmw_private *dev_priv)
-{
- return 0;
+
+ return ret;
}
-#endif
static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{
@@ -1582,7 +1565,7 @@ static const struct file_operations vmwgfx_driver_fops = {
};
static struct drm_driver driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+ .driver_features =
DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC,
.load = vmw_driver_load,
.unload = vmw_driver_unload,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index cd607ba9c2fe..accb2fafe2f1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -1337,18 +1337,15 @@ static inline void vmw_bo_unreference(struct vmw_buffer_object **buf)
*buf = NULL;
if (tmp_buf != NULL) {
- struct ttm_buffer_object *bo = &tmp_buf->base;
-
- ttm_bo_unref(&bo);
+ ttm_bo_put(&tmp_buf->base);
}
}
static inline struct vmw_buffer_object *
vmw_bo_reference(struct vmw_buffer_object *buf)
{
- if (ttm_bo_reference(&buf->base))
- return buf;
- return NULL;
+ ttm_bo_get(&buf->base);
+ return buf;
}
static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index f2d13a72c05d..88b8178d4687 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -3570,7 +3570,7 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
*p_fence = NULL;
}
- return 0;
+ return ret;
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b351fb5214d3..ed2f67822f45 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1646,7 +1646,7 @@ static int vmw_kms_check_topology(struct drm_device *dev,
struct drm_connector_state *conn_state;
struct vmw_connector_state *vmw_conn_state;
- if (!du->pref_active) {
+ if (!du->pref_active && new_crtc_state->enable) {
ret = -EINVAL;
goto clean;
}
@@ -2554,8 +2554,8 @@ void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv,
user_fence_rep)
{
struct vmw_fence_obj *fence = NULL;
- uint32_t handle;
- int ret;
+ uint32_t handle = 0;
+ int ret = 0;
if (file_priv || user_fence_rep || vmw_validation_has_bos(ctx) ||
out_fence)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 655abbcd4058..535b03599e55 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -29,8 +29,8 @@
#define VMWGFX_KMS_H_
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_probe_helper.h>
#include "vmwgfx_drv.h"
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index 7ed179d30ec5..d83cc66e1210 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -300,7 +300,8 @@ out_no_setup:
&batch->otables[i]);
}
- ttm_bo_unref(&batch->otable_bo);
+ ttm_bo_put(batch->otable_bo);
+ batch->otable_bo = NULL;
out_no_bo:
return ret;
}
@@ -365,7 +366,8 @@ static void vmw_otable_batch_takedown(struct vmw_private *dev_priv,
vmw_bo_fence_single(bo, NULL);
ttm_bo_unreserve(bo);
- ttm_bo_unref(&batch->otable_bo);
+ ttm_bo_put(batch->otable_bo);
+ batch->otable_bo = NULL;
}
/*
@@ -463,7 +465,8 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
out_unreserve:
ttm_bo_unreserve(mob->pt_bo);
- ttm_bo_unref(&mob->pt_bo);
+ ttm_bo_put(mob->pt_bo);
+ mob->pt_bo = NULL;
return ret;
}
@@ -580,8 +583,10 @@ static void vmw_mob_pt_setup(struct vmw_mob *mob,
*/
void vmw_mob_destroy(struct vmw_mob *mob)
{
- if (mob->pt_bo)
- ttm_bo_unref(&mob->pt_bo);
+ if (mob->pt_bo) {
+ ttm_bo_put(mob->pt_bo);
+ mob->pt_bo = NULL;
+ }
kfree(mob);
}
@@ -698,8 +703,10 @@ int vmw_mob_bind(struct vmw_private *dev_priv,
out_no_cmd_space:
vmw_fifo_resource_dec(dev_priv);
- if (pt_set_up)
- ttm_bo_unref(&mob->pt_bo);
+ if (pt_set_up) {
+ ttm_bo_put(mob->pt_bo);
+ mob->pt_bo = NULL;
+ }
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 3025bfc001a1..a7c30e567f09 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -461,7 +461,8 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
}
INIT_LIST_HEAD(&val_list);
- val_buf->bo = ttm_bo_reference(&res->backup->base);
+ ttm_bo_get(&res->backup->base);
+ val_buf->bo = &res->backup->base;
val_buf->num_shared = 0;
list_add_tail(&val_buf->head, &val_list);
ret = ttm_eu_reserve_buffers(ticket, &val_list, interruptible, NULL);
@@ -484,7 +485,8 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
out_no_validate:
ttm_eu_backoff_reservation(ticket, &val_list);
out_no_reserve:
- ttm_bo_unref(&val_buf->bo);
+ ttm_bo_put(val_buf->bo);
+ val_buf->bo = NULL;
if (backup_dirty)
vmw_bo_unreference(&res->backup);
@@ -544,7 +546,8 @@ vmw_resource_backoff_reservation(struct ww_acquire_ctx *ticket,
INIT_LIST_HEAD(&val_list);
list_add_tail(&val_buf->head, &val_list);
ttm_eu_backoff_reservation(ticket, &val_list);
- ttm_bo_unref(&val_buf->bo);
+ ttm_bo_put(val_buf->bo);
+ val_buf->bo = NULL;
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
index b3f547fc5d3d..e9944ac2e057 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
@@ -628,8 +628,10 @@ void vmw_validation_unref_lists(struct vmw_validation_context *ctx)
struct vmw_validation_bo_node *entry;
struct vmw_validation_res_node *val;
- list_for_each_entry(entry, &ctx->bo_list, base.head)
- ttm_bo_unref(&entry->base.bo);
+ list_for_each_entry(entry, &ctx->bo_list, base.head) {
+ ttm_bo_put(entry->base.bo);
+ entry->base.bo = NULL;
+ }
list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list);
list_for_each_entry(val, &ctx->resource_list, head)
diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
index 4d3d36fc3a5d..3e78a832d7f9 100644
--- a/drivers/gpu/drm/xen/xen_drm_front.c
+++ b/drivers/gpu/drm/xen/xen_drm_front.c
@@ -10,7 +10,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drm_gem.h>
#include <linux/of_device.h>
diff --git a/drivers/gpu/drm/xen/xen_drm_front_conn.c b/drivers/gpu/drm/xen/xen_drm_front_conn.c
index 54af2669b1b3..9f5f31f77f1e 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_conn.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_conn.c
@@ -9,7 +9,7 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
index 28bc501af450..53c376d55fcf 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -11,9 +11,9 @@
#include "xen_drm_front_gem.h"
#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
+#include <drm/drm_probe_helper.h>
#include <linux/dma-buf.h>
#include <linux/scatterlist.h>
@@ -235,8 +235,14 @@ static int gem_mmap_obj(struct xen_gem_object *xen_obj,
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_flags |= VM_MIXEDMAP;
vma->vm_pgoff = 0;
- vma->vm_page_prot =
- pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ /*
+ * According to Xen on ARM ABI (xen/include/public/arch-arm.h):
+ * all memory which is shared with other entities in the system
+ * (including the hypervisor and other guests) must reside in memory
+ * which is mapped as Normal Inner Write-Back Outer Write-Back
+ * Inner-Shareable.
+ */
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
/*
* vm_operations_struct.fault handler will be called if CPU access
@@ -282,8 +288,9 @@ void *xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj)
if (!xen_obj->pages)
return NULL;
+ /* Please see comment in gem_mmap_obj on mapping and attributes. */
return vmap(xen_obj->pages, xen_obj->num_pages,
- VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+ VM_MAP, PAGE_KERNEL);
}
void xen_drm_front_gem_prime_vunmap(struct drm_gem_object *gem_obj,
diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c
index a3479eb72d79..c2955d375394 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_kms.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c
@@ -13,9 +13,9 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_probe_helper.h>
#include "xen_drm_front.h"
#include "xen_drm_front_conn.h"
@@ -54,7 +54,7 @@ fb_create(struct drm_device *dev, struct drm_file *filp,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct xen_drm_front_drm_info *drm_info = dev->dev_private;
- static struct drm_framebuffer *fb;
+ struct drm_framebuffer *fb;
struct drm_gem_object *gem_obj;
int ret;
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index f5ea32ae8600..28e8d6072910 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -18,12 +18,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "zx_drm_drv.h"
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
index 9fc98bb4f3d9..df522d74bebf 100644
--- a/drivers/gpu/drm/zte/zx_hdmi.c
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -20,9 +20,9 @@
#include <linux/of_device.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include <sound/hdmi-codec.h>
diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
index b73afb212fb2..87b5d86413d2 100644
--- a/drivers/gpu/drm/zte/zx_tvenc.c
+++ b/drivers/gpu/drm/zte/zx_tvenc.c
@@ -14,7 +14,7 @@
#include <linux/regmap.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "zx_drm_drv.h"
diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c
index 23d1ff4355a0..e14c1d709740 100644
--- a/drivers/gpu/drm/zte/zx_vga.c
+++ b/drivers/gpu/drm/zte/zx_vga.c
@@ -13,7 +13,7 @@
#include <linux/regmap.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "zx_drm_drv.h"
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index 442311d31110..15400ffb1d22 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -15,12 +15,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include "zx_common_regs.h"