summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c148
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c106
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c43
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c67
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h47
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c169
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h168
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma_types.h163
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c26
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom.c29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c475
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c83
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v12_1.c247
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c55
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c63
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c71
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c197
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c89
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c82
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c59
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c34
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dma.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc15_common.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc_v1_0.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c11
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c72
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c23
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c61
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c71
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c2
-rw-r--r--drivers/gpu/drm/amd/display/Makefile1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c113
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h42
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c20
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c11
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c3
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c64
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h28
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c21
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c61
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h19
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c36
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c1613
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c19
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c8
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c34
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c83
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c2041
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c357
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile3
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c254
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c246
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c147
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_state.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c124
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h48
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c50
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_memory_pool.c277
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_memory_pool.h107
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c44
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c108
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c27
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c117
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h14
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c39
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c285
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h17
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c199
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h70
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h65
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h140
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_service.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h18
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_factory.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c680
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h714
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h238
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/os_types.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c56
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c123
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/rmcm/Makefile44
-rw-r--r--drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c867
-rw-r--r--drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h717
-rw-r--r--drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c251
-rw-r--r--drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h35
-rw-r--r--drivers/gpu/drm/amd/display/dmub/dmub_srv.h2
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c7
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_power.h3
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_replay.c13
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c5
-rw-r--r--drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h7
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c36
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c4
248 files changed, 9495 insertions, 4907 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 63c4c3c1164a..4752e445bc56 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1218,7 +1218,7 @@ AMD KFD
M: Felix Kuehling <Felix.Kuehling@amd.com>
L: amd-gfx@lists.freedesktop.org
S: Supported
-T: git https://gitlab.freedesktop.org/agd5f/linux.git
+T: git https://gitlab.freedesktop.org/drm/amdgpu/kernel.git
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd*.[ch]
F: drivers/gpu/drm/amd/amdkfd/
F: drivers/gpu/drm/amd/include/cik_structs.h
@@ -22708,7 +22708,7 @@ L: amd-gfx@lists.freedesktop.org
S: Supported
B: https://gitlab.freedesktop.org/drm/amd/-/issues
C: irc://irc.oftc.net/radeon
-T: git https://gitlab.freedesktop.org/agd5f/linux.git
+T: git https://gitlab.freedesktop.org/drm/amdgpu/kernel.git
F: Documentation/gpu/amdgpu/
F: drivers/gpu/drm/amd/
F: drivers/gpu/drm/ci/xfails/amd*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 79b69d74eb2e..6c1c775256fd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -79,7 +79,7 @@
#include "amdgpu_umsch_mm.h"
#include "amdgpu_gmc.h"
#include "amdgpu_gfx.h"
-#include "amdgpu_sdma.h"
+#include "amdgpu_sdma_types.h"
#include "amdgpu_lsdma.h"
#include "amdgpu_nbio.h"
#include "amdgpu_reg_access.h"
@@ -626,6 +626,9 @@ enum amdgpu_enforce_isolation_mode {
struct amdgpu_device {
struct device *dev;
struct pci_dev *pdev;
+ /* The two ends of the physical PCIe link outside the device. */
+ struct pci_dev *link_dev;
+ struct pci_dev *link_partner;
struct drm_device ddev;
#ifdef CONFIG_DRM_AMD_ACP
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 09feb45584ba..afcfb92fb9f5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -245,6 +245,25 @@ void amdgpu_amdkfd_device_fini_sw(struct amdgpu_device *adev)
}
}
+int amdgpu_amdkfd_prepare_partition_switch(struct amdgpu_device *adev)
+{
+ struct kfd_dev *kfd = adev->kfd.dev;
+ int r;
+
+ if (!kfd)
+ return 0;
+ r = kgd2kfd_check_and_lock_kfd(kfd);
+ if (r)
+ return r;
+
+ adev->kfd.init_complete = false;
+ kgd2kfd_device_fini(kfd);
+ adev->kfd.dev = NULL;
+ amdgpu_amdkfd_total_mem_size -= adev->gmc.real_vram_size;
+
+ return 0;
+}
+
void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,
const void *ih_ring_entry)
{
@@ -330,7 +349,7 @@ void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
struct kfd_dev *kfd = adev->kfd.dev;
unsigned int i;
- if (!kfd)
+ if (!kfd || !kfd->init_complete)
return;
for (i = 0; i < kfd->num_nodes; i++) {
@@ -817,16 +836,6 @@ int amdgpu_amdkfd_send_close_event_drain_irq(struct amdgpu_device *adev,
return 0;
}
-int amdgpu_amdkfd_check_and_lock_kfd(struct amdgpu_device *adev)
-{
- return kgd2kfd_check_and_lock_kfd(adev->kfd.dev);
-}
-
-void amdgpu_amdkfd_unlock_kfd(struct amdgpu_device *adev)
-{
- kgd2kfd_unlock_kfd(adev->kfd.dev);
-}
-
u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int xcp_id)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 1b7dc0d3963b..e3da382ceb3c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -170,8 +170,7 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,
void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev);
void amdgpu_amdkfd_device_init(struct amdgpu_device *adev);
void amdgpu_amdkfd_device_fini_sw(struct amdgpu_device *adev);
-int amdgpu_amdkfd_check_and_lock_kfd(struct amdgpu_device *adev);
-void amdgpu_amdkfd_unlock_kfd(struct amdgpu_device *adev);
+int amdgpu_amdkfd_prepare_partition_switch(struct amdgpu_device *adev);
int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev,
enum kgd_engine_type engine,
uint32_t vmid, uint64_t gpu_addr,
@@ -431,6 +430,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf);
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_device_fini(struct kfd_dev *kfd);
void kgd2kfd_suspend(struct kfd_dev *kfd, bool suspend_proc);
int kgd2kfd_resume(struct kfd_dev *kfd, bool resume_proc);
void kgd2kfd_suspend_process(struct kfd_dev *kfd);
@@ -485,6 +485,10 @@ static inline void kgd2kfd_device_exit(struct kfd_dev *kfd)
{
}
+static inline void kgd2kfd_device_fini(struct kfd_dev *kfd)
+{
+}
+
static inline void kgd2kfd_suspend(struct kfd_dev *kfd, bool suspend_proc)
{
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
index 7e9f7a280c1b..98cd0435ced5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c
@@ -193,5 +193,6 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = {
.program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
.hqd_get_pq_addr = kgd_gfx_v9_hqd_get_pq_addr,
.hqd_reset = kgd_gfx_v9_hqd_reset,
- .hqd_sdma_get_doorbell = kgd_gfx_v9_hqd_sdma_get_doorbell
+ .hqd_sdma_get_doorbell = kgd_gfx_v9_hqd_sdma_get_doorbell,
+ .hqd_gfx_clean_fault = kgd_gfx_v9_clean_fault
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c
index bc079b95fc52..4626e0b13909 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c
@@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_amdkfd.h"
#include "amdgpu_amdkfd_gfx_v9.h"
#include "amdgpu_amdkfd_aldebaran.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
index bc48b2ba30d1..1550e275f0ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
@@ -1091,6 +1091,153 @@ uint32_t kgd_gfx_v10_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
return 0;
}
+static void lock_spi_csq_mutexes(struct amdgpu_device *adev)
+{
+ mutex_lock(&adev->srbm_mutex);
+ mutex_lock(&adev->grbm_idx_mutex);
+
+}
+
+static void unlock_spi_csq_mutexes(struct amdgpu_device *adev)
+{
+ mutex_unlock(&adev->grbm_idx_mutex);
+ mutex_unlock(&adev->srbm_mutex);
+}
+
+/**
+ * get_wave_count: Read device registers to get number of waves in flight for
+ * a particular queue. The method also returns the doorbell offset associated
+ * with the queue.
+ *
+ * @adev: Handle of device whose registers are to be read
+ * @queue_idx: Index of queue in the queue-map bit-field
+ * @queue_cnt: Stores the wave count and doorbell offset for an active queue
+ * @inst: xcc's instance number on a multi-XCC setup
+ */
+static void get_wave_count(struct amdgpu_device *adev, int queue_idx,
+ struct kfd_cu_occupancy *queue_cnt, uint32_t inst)
+{
+ int pipe_idx;
+ int queue_slot;
+ unsigned int reg_val;
+ unsigned int wave_cnt;
+ /*
+ * Program GRBM with appropriate MEID, PIPEID, QUEUEID and VMID
+ * parameters to read out waves in flight. Get doorbell offset if there are
+ * non-zero waves in flight.
+ */
+ pipe_idx = queue_idx / adev->gfx.mec.num_queue_per_pipe;
+ queue_slot = queue_idx % adev->gfx.mec.num_queue_per_pipe;
+ nv_grbm_select(adev, 1, pipe_idx, queue_slot, 0);
+ reg_val = RREG32_SOC15_IP(GC, SOC15_REG_OFFSET(GC, 0,
+ mmSPI_CSQ_WF_ACTIVE_COUNT_0) + queue_slot);
+ wave_cnt = reg_val & SPI_CSQ_WF_ACTIVE_COUNT_0__COUNT_MASK;
+ if (wave_cnt != 0) {
+ queue_cnt->wave_cnt += wave_cnt;
+ queue_cnt->doorbell_off =
+ (RREG32_SOC15(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL) &
+ CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
+ CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ }
+}
+
+/**
+ * kgd_gfx_v10_get_cu_occupancy: Reads relevant registers associated with each
+ * shader engine and aggregates the number of waves that are in flight for the
+ * process whose pasid is provided as a parameter. The process could have ZERO
+ * or more queues running and submitting waves to compute units.
+ *
+ * @adev: Handle of device from which to get number of waves in flight
+ * @cu_occupancy: Array that gets filled with wave_cnt and doorbell offset
+ * for comparison later.
+ * @max_waves_per_cu: Output parameter updated with maximum number of waves
+ * possible per Compute Unit
+ * @inst: xcc's instance number on a multi-XCC setup
+ *
+ * Note: It's possible that the device has too many queues (oversubscription)
+ * in which case a VMID could be remapped to a different PASID. This could lead
+ * to an inaccurate wave count. Following is a high-level sequence:
+ * Time T1: vmid = getVmid(); vmid is associated with Pasid P1
+ * Time T2: passId = getPasId(vmid); vmid is associated with Pasid P2
+ * In the sequence above wave count obtained from time T1 will be incorrectly
+ * lost or added to total wave count.
+ *
+ * The registers that provide the waves in flight are:
+ *
+ * SPI_CSQ_WF_ACTIVE_STATUS - bit-map of queues per pipe. The bit is ON if a
+ * queue is slotted, OFF if there is no queue. A process could have ZERO or
+ * more queues slotted and submitting waves to be run on compute units. Even
+ * when there is a queue it is possible there could be zero wave fronts, this
+ * can happen when queue is waiting on top-of-pipe events - e.g. waitRegMem
+ * command
+ *
+ * For each bit that is ON from above:
+ *
+ * Read (SPI_CSQ_WF_ACTIVE_COUNT_0 + queue_idx) register. It provides the
+ * number of waves that are in flight for the queue at specified index. The
+ * index ranges from 0 to 7.
+ *
+ * If non-zero waves are in flight, store the corresponding doorbell offset
+ * of the queue, along with the wave count.
+ *
+ * Determine if the queue belongs to the process by comparing the doorbell
+ * offset against the process's queues. If it matches, aggregate the wave
+ * count for the process.
+ *
+ * Reading registers referenced above involves programming GRBM appropriately
+ */
+void kgd_gfx_v10_get_cu_occupancy(struct amdgpu_device *adev,
+ struct kfd_cu_occupancy *cu_occupancy,
+ int *max_waves_per_cu, uint32_t inst)
+{
+ int qidx;
+ int se_idx;
+ int se_cnt;
+ int queue_map;
+ int max_queue_cnt;
+ DECLARE_BITMAP(cp_queue_bitmap, AMDGPU_MAX_QUEUES);
+
+ lock_spi_csq_mutexes(adev);
+ nv_grbm_select(adev, 1, 0, 0, 0);
+
+ /*
+ * Iterate through the shader engines and arrays of the device
+ * to get number of waves in flight
+ */
+ bitmap_complement(cp_queue_bitmap, adev->gfx.mec_bitmap[0].queue_bitmap,
+ AMDGPU_MAX_QUEUES);
+ max_queue_cnt = adev->gfx.mec.num_pipe_per_mec *
+ adev->gfx.mec.num_queue_per_pipe;
+ se_cnt = adev->gfx.config.max_shader_engines;
+ for (se_idx = 0; se_idx < se_cnt; se_idx++) {
+ amdgpu_gfx_select_se_sh(adev, se_idx, 0, 0xffffffff, inst);
+ queue_map = RREG32_SOC15(GC, 0,
+ mmSPI_CSQ_WF_ACTIVE_STATUS);
+
+ for (qidx = 0; qidx < max_queue_cnt; qidx++) {
+ /* Skip queues that are not associated with
+ * compute functions
+ */
+ if (!test_bit(qidx, cp_queue_bitmap))
+ continue;
+
+ if (!(queue_map & (1 << qidx)))
+ continue;
+
+ /* Get number of waves in flight and aggregate them */
+ get_wave_count(adev, qidx, &cu_occupancy[qidx], inst);
+ }
+ }
+
+ amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, inst);
+ nv_grbm_select(adev, 0, 0, 0, 0);
+ unlock_spi_csq_mutexes(adev);
+
+ /* Update the output parameters and return */
+ *max_waves_per_cu = adev->gfx.cu_info.simd_per_cu *
+ adev->gfx.cu_info.max_waves_per_simd;
+}
+
const struct kfd2kgd_calls gfx_v10_kfd2kgd = {
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
@@ -1120,5 +1267,6 @@ const struct kfd2kgd_calls gfx_v10_kfd2kgd = {
.program_trap_handler_settings = program_trap_handler_settings,
.hqd_get_pq_addr = kgd_gfx_v10_hqd_get_pq_addr,
.hqd_reset = kgd_gfx_v10_hqd_reset,
+ .get_cu_occupancy = kgd_gfx_v10_get_cu_occupancy,
.hqd_sdma_get_doorbell = kgd_gfx_v10_hqd_sdma_get_doorbell
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h
index df350ea67c30..a91b638c6bcd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h
@@ -69,3 +69,6 @@ uint64_t kgd_gfx_v10_hqd_reset(struct amdgpu_device *adev,
unsigned int utimeout);
uint32_t kgd_gfx_v10_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
int engine, int queue);
+void kgd_gfx_v10_get_cu_occupancy(struct amdgpu_device *adev,
+ struct kfd_cu_occupancy *cu_occupancy,
+ int *max_waves_per_cu, uint32_t inst);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c
index e31afee42979..50535563efa8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c
@@ -683,5 +683,6 @@ const struct kfd2kgd_calls gfx_v10_3_kfd2kgd = {
.clear_address_watch = kgd_gfx_v10_clear_address_watch,
.hqd_get_pq_addr = kgd_gfx_v10_hqd_get_pq_addr,
.hqd_reset = kgd_gfx_v10_hqd_reset,
+ .get_cu_occupancy = kgd_gfx_v10_get_cu_occupancy,
.hqd_sdma_get_doorbell = kgd_gfx_v10_hqd_sdma_get_doorbell
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
index b30ad9701bce..0d62cf475f40 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
@@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_amdkfd.h"
#include "gc/gc_9_0_offset.h"
#include "gc/gc_9_0_sh_mask.h"
@@ -37,6 +38,7 @@
#include "soc15.h"
#include "soc15d.h"
#include "gfx_v9_0.h"
+#include "gfx_v9_4_2.h"
#include "amdgpu_amdkfd_gfx_v9.h"
#include <uapi/linux/kfd_ioctl.h>
@@ -1226,11 +1228,15 @@ unlock_out:
uint32_t kgd_gfx_v9_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
int engine, int queue)
-
{
return 0;
}
+void kgd_gfx_v9_clean_fault(struct amdgpu_device *adev)
+{
+ gfx_v9_4_2_clean_fault(adev);
+}
+
const struct kfd2kgd_calls gfx_v9_kfd2kgd = {
.program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping,
@@ -1261,5 +1267,6 @@ const struct kfd2kgd_calls gfx_v9_kfd2kgd = {
.program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
.hqd_get_pq_addr = kgd_gfx_v9_hqd_get_pq_addr,
.hqd_reset = kgd_gfx_v9_hqd_reset,
- .hqd_sdma_get_doorbell = kgd_gfx_v9_hqd_sdma_get_doorbell
+ .hqd_sdma_get_doorbell = kgd_gfx_v9_hqd_sdma_get_doorbell,
+ .hqd_gfx_clean_fault = kgd_gfx_v9_clean_fault
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
index 9f43f16a1ace..dba7ace872de 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
@@ -115,3 +115,4 @@ uint64_t kgd_gfx_v9_hqd_reset(struct amdgpu_device *adev,
unsigned int utimeout);
uint32_t kgd_gfx_v9_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
int engine, int queue);
+void kgd_gfx_v9_clean_fault(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index d53259a5b82f..acafa8c59cc9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -532,7 +532,7 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
out->state.flags = 0x0;
out->state.hangs = 0x0;
- /* determine if a GPU reset has occured since the last call */
+ /* determine if a GPU reset has occurred since the last call */
reset_counter = atomic_read(&adev->gpu_reset_counter);
/* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
if (ctx->reset_counter_query == reset_counter)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index d80fe17556da..d8786a93a851 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -36,6 +36,7 @@
#include "amdgpu_rap.h"
#include "amdgpu_securedisplay.h"
#include "amdgpu_fw_attestation.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_umr.h"
#include "amdgpu_reset.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 25ce45b2aef1..494aa2faef95 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -68,6 +68,7 @@
#include "amdgpu_vf_error.h"
#include "amdgpu_amdkfd.h"
+#include "amdgpu_ip.h"
#include "amdgpu_pm.h"
#include "amdgpu_xgmi.h"
@@ -1353,31 +1354,6 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
#endif
}
-/*
- * Some dGPUs expose their display endpoint below an internal PCIe switch.
- * Use the switch upstream port to query the host-facing link.
- */
-static struct pci_dev *amdgpu_device_get_aspm_pdev(struct amdgpu_device *adev)
-{
- struct pci_dev *swds, *swus;
-
- swds = pci_upstream_bridge(adev->pdev);
- if (!swds ||
- (swds->vendor != PCI_VENDOR_ID_ATI &&
- swds->vendor != PCI_VENDOR_ID_AMD) ||
- pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM)
- return adev->pdev;
-
- swus = pci_upstream_bridge(swds);
- if (!swus ||
- (swus->vendor != PCI_VENDOR_ID_ATI &&
- swus->vendor != PCI_VENDOR_ID_AMD) ||
- pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM)
- return adev->pdev;
-
- return swus;
-}
-
/**
* amdgpu_device_should_use_aspm - check if the device should program ASPM
*
@@ -1413,7 +1389,7 @@ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
* the immediate upstream bridge. Use SWUS for dGPUs with an
* internal switch so that this is the host-facing link.
*/
- aspm_pdev = amdgpu_device_get_aspm_pdev(adev);
+ aspm_pdev = adev->link_dev;
parent = pci_upstream_bridge(aspm_pdev);
if (!parent) {
dev_dbg(adev->dev, "ASPM: no upstream PCIe link for %s\n",
@@ -1966,18 +1942,28 @@ static void amdgpu_uid_fini(struct amdgpu_device *adev)
adev->uid_info = NULL;
}
-static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
+static void amdgpu_device_init_pcie_links(struct amdgpu_device *adev)
{
- struct pci_dev *parent = adev->pdev;
+ struct pci_dev *swds, *swus;
- /* skip upstream/downstream switches internal to dGPU */
- while ((parent = pci_upstream_bridge(parent))) {
- if (parent->vendor == PCI_VENDOR_ID_ATI)
- continue;
- break;
- }
+ adev->link_dev = adev->pdev;
+ adev->link_partner = pci_upstream_bridge(adev->link_dev);
+
+ /* Skip an upstream/downstream switch internal to the dGPU. */
+ swds = adev->link_partner;
+ if (!swds || swds->vendor != PCI_VENDOR_ID_ATI ||
+ pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM)
+ return;
+
+ swus = pci_upstream_bridge(swds);
+ if (!swus ||
+ (swus->vendor != PCI_VENDOR_ID_ATI &&
+ swus->vendor != PCI_VENDOR_ID_AMD) ||
+ pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM)
+ return;
- return parent;
+ adev->link_dev = swus;
+ adev->link_partner = pci_upstream_bridge(swus);
}
/**
@@ -1993,7 +1979,6 @@ static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
{
struct amdgpu_ip_block *ip_block;
- struct pci_dev *parent;
bool total, skip_bios, early_full_gpu_access = false;
uint32_t bios_flags;
int i, r;
@@ -2089,10 +2074,9 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
!dev_is_removable(&adev->pdev->dev))
adev->flags |= AMD_IS_PX;
- if (!(adev->flags & AMD_IS_APU)) {
- parent = amdgpu_device_find_parent(adev);
- adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
- }
+ if (!(adev->flags & AMD_IS_APU))
+ adev->has_pr3 = adev->link_partner &&
+ pci_pr3_present(adev->link_partner);
adev->pm.pp_feature = amdgpu_pp_feature_mask;
if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS)
@@ -3791,6 +3775,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
adev->shutdown = false;
adev->flags = flags;
+ amdgpu_device_init_pcie_links(adev);
if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST)
adev->asic_type = amdgpu_force_asic_type;
@@ -3857,6 +3842,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
spin_lock_init(&adev->irq.lock);
+ amdgpu_ip_map_init(adev);
amdgpu_early_init_rlc_reg_funcs(adev);
amdgpu_device_init_apu_flags(adev);
@@ -4353,7 +4339,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
void amdgpu_device_fini_sw(struct amdgpu_device *adev)
{
- int i, idx;
+ int i;
bool px;
amdgpu_device_ip_fini(adev);
@@ -4395,11 +4381,9 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
vga_client_unregister(adev->pdev);
- if (drm_dev_enter(adev_to_drm(adev), &idx)) {
-
+ if (adev->rmmio) {
iounmap(adev->rmmio);
adev->rmmio = NULL;
- drm_dev_exit(idx);
}
if (IS_ENABLED(CONFIG_PERF_EVENTS))
@@ -5888,11 +5872,9 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
*width = PCIE_LNK_WIDTH_UNKNOWN;
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
- struct pci_dev *parent = amdgpu_device_find_parent(adev);
-
- if (parent) {
- *speed = pcie_get_speed_cap(parent);
- *width = pcie_get_width_cap(parent);
+ if (adev->link_partner) {
+ *speed = pcie_get_speed_cap(adev->link_partner);
+ *width = pcie_get_width_cap(adev->link_partner);
}
} else {
/* use the current speeds rather than max if switching is not supported */
@@ -5914,21 +5896,11 @@ static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
enum pci_bus_speed *speed,
enum pcie_link_width *width)
{
- struct pci_dev *parent = adev->pdev;
-
if (!speed || !width)
return;
- /* use the device itself */
- *speed = pcie_get_speed_cap(adev->pdev);
- *width = pcie_get_width_cap(adev->pdev);
-
- /* use the link outside the device */
- parent = amdgpu_device_find_parent(adev);
- if (parent) {
- *speed = pcie_get_speed_cap(parent);
- *width = pcie_get_width_cap(parent);
- }
+ *speed = pcie_get_speed_cap(adev->link_dev);
+ *width = pcie_get_width_cap(adev->link_dev);
}
/**
@@ -6450,16 +6422,10 @@ static void amdgpu_device_cache_switch_state(struct amdgpu_device *adev)
struct pci_dev *swus, *swds;
int r;
- swds = pci_upstream_bridge(adev->pdev);
- if (!swds || swds->vendor != PCI_VENDOR_ID_ATI ||
- pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM)
- return;
- swus = pci_upstream_bridge(swds);
- if (!swus ||
- (swus->vendor != PCI_VENDOR_ID_ATI &&
- swus->vendor != PCI_VENDOR_ID_AMD) ||
- pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM)
+ swus = adev->link_dev != adev->pdev ? adev->link_dev : NULL;
+ if (!swus)
return;
+ swds = pci_upstream_bridge(adev->pdev);
/* If already saved, return */
if (adev->pcie_reset_ctx.swus)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 4fd90e478bd2..ad21986d7b1b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -3281,8 +3281,7 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &mes_v12_1_ip_block);
adev->enable_mes = true;
adev->enable_mes_kiq = true;
- if (amdgpu_uni_mes)
- adev->enable_uni_mes = true;
+ adev->enable_uni_mes = true;
break;
default:
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index b4fbd8a407f1..4031ebe075d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -43,6 +43,7 @@
#include <linux/dma-buf.h>
#include <linux/dma-fence-array.h>
#include <linux/pci-p2pdma.h>
+#include <linux/pm_runtime.h>
static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops;
@@ -100,15 +101,54 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0)
attach->peer2peer = false;
+ /*
+ * Only allow P2P while the exporter is active, and keep it active
+ * until detach. With runtime PM disabled take a plain reference so
+ * the put in detach stays balanced.
+ */
+ if (attach->peer2peer) {
+ struct device *dev = adev_to_drm(adev)->dev;
+ int ret = pm_runtime_get_if_active(dev);
+
+ if (!ret)
+ attach->peer2peer = false;
+ else if (ret < 0)
+ pm_runtime_get_noresume(dev);
+ }
+
r = dma_resv_lock(bo->tbo.base.resv, NULL);
if (r)
- return r;
+ goto err_pm_put;
amdgpu_vm_bo_update_shared(bo);
dma_resv_unlock(bo->tbo.base.resv);
return 0;
+
+err_pm_put:
+ if (attach->peer2peer)
+ pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ return r;
+}
+
+/**
+ * amdgpu_dma_buf_detach - &dma_buf_ops.detach implementation
+ *
+ * @dmabuf: DMA-buf where we remove the attachment from
+ * @attach: the attachment to remove
+ *
+ * Drop the runtime PM reference taken in amdgpu_dma_buf_attach().
+ */
+static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attach)
+{
+ struct drm_gem_object *obj = dmabuf->priv;
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+
+ if (attach->peer2peer)
+ pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
}
/**
@@ -350,6 +390,7 @@ static void amdgpu_dma_buf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map
const struct dma_buf_ops amdgpu_dmabuf_ops = {
.attach = amdgpu_dma_buf_attach,
+ .detach = amdgpu_dma_buf_detach,
.pin = amdgpu_dma_buf_pin,
.unpin = amdgpu_dma_buf_unpin,
.map_dma_buf = amdgpu_dma_buf_map,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index a6f95ff47d24..7a132e6d7e42 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -1235,7 +1235,8 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t xcc_
if (adev->mes.ring[0].sched.ready)
return amdgpu_mes_rreg(adev, reg, xcc_id);
- BUG_ON(!ring->funcs->emit_rreg);
+ if (!ring->funcs || !ring->funcs->emit_rreg)
+ goto failed_kiq_read;
spin_lock_irqsave(&kiq->ring_lock, flags);
if (amdgpu_wb_get(adev, &reg_val_offs)) {
@@ -1303,8 +1304,6 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id];
struct amdgpu_ring *ring = &kiq->ring;
- BUG_ON(!ring->funcs->emit_wreg);
-
if (amdgpu_device_skip_hw_access(adev))
return;
@@ -1313,6 +1312,9 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
return;
}
+ if (!ring->funcs || !ring->funcs->emit_wreg)
+ goto failed_kiq_write;
+
spin_lock_irqsave(&kiq->ring_lock, flags);
r = amdgpu_ring_alloc(ring, 32);
if (r)
@@ -1409,9 +1411,8 @@ int amdgpu_kiq_hdp_flush(struct amdgpu_device *adev)
if (adev->enable_mes_kiq && adev->mes.ring[0].sched.ready)
return amdgpu_mes_hdp_flush(adev);
- if (!ring->funcs->emit_hdp_flush) {
+ if (!ring->funcs || !ring->funcs->emit_hdp_flush)
return -EOPNOTSUPP;
- }
spin_lock_irqsave(&kiq->ring_lock, flags);
r = amdgpu_ring_alloc(ring, 32);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 7c0554506334..1bf2a42fa63c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -33,6 +33,8 @@
#include "amdgpu_gmc.h"
#include "amdgpu_ras.h"
#include "amdgpu_reset.h"
+#include "amdgpu_ring.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_atomfirmware.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 8c32c6943764..5e424e3b6e71 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -228,12 +228,12 @@ fallback:
*/
/**
- * amdgpu_vmid_had_gpu_reset - check if reset occured since last use
+ * amdgpu_vmid_had_gpu_reset - check if reset occurred since last use
*
* @adev: amdgpu_device pointer
* @id: VMID structure
*
- * Check if GPU reset occured since last use of the VMID.
+ * Check if GPU reset occurred since last use of the VMID.
*/
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
struct amdgpu_vmid *id)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c
index a426327f2141..734f2a0bc79a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c
@@ -24,39 +24,16 @@
#include "amdgpu.h"
#include "amdgpu_ip.h"
-static int8_t amdgpu_logical_to_dev_inst(struct amdgpu_device *adev,
- enum amd_hw_ip_block_type block,
- int8_t inst)
+u32 amdgpu_ip_map_logical_to_dev_mask(struct amdgpu_ip_map_info *ip_map,
+ enum amd_hw_ip_block_type block,
+ u32 mask)
{
- int8_t dev_inst;
-
- switch (block) {
- case GC_HWIP:
- case SDMA0_HWIP:
- /* Both JPEG and VCN as JPEG is only alias of VCN */
- case VCN_HWIP:
- dev_inst = adev->ip_map.dev_inst[block][inst];
- break;
- default:
- /* For rest of the IPs, no look up required.
- * Assume 'logical instance == physical instance' for all configs. */
- dev_inst = inst;
- break;
- }
-
- return dev_inst;
-}
-
-static uint32_t amdgpu_logical_to_dev_mask(struct amdgpu_device *adev,
- enum amd_hw_ip_block_type block,
- uint32_t mask)
-{
- uint32_t dev_mask = 0;
- int8_t log_inst, dev_inst;
+ unsigned int log_inst, dev_inst;
+ u32 dev_mask = 0;
while (mask) {
log_inst = ffs(mask) - 1;
- dev_inst = amdgpu_logical_to_dev_inst(adev, block, log_inst);
+ dev_inst = ip_map->dev_inst[block][log_inst];
dev_mask |= (1 << dev_inst);
mask &= ~(1 << log_inst);
}
@@ -64,35 +41,15 @@ static uint32_t amdgpu_logical_to_dev_mask(struct amdgpu_device *adev,
return dev_mask;
}
-static void amdgpu_populate_ip_map(struct amdgpu_device *adev,
- enum amd_hw_ip_block_type ip_block,
- uint32_t inst_mask)
-{
- int l = 0, i;
-
- while (inst_mask) {
- i = ffs(inst_mask) - 1;
- adev->ip_map.dev_inst[ip_block][l++] = i;
- inst_mask &= ~(1 << i);
- }
- for (; l < HWIP_MAX_INSTANCE; l++)
- adev->ip_map.dev_inst[ip_block][l] = -1;
-}
-
void amdgpu_ip_map_init(struct amdgpu_device *adev)
{
- u32 ip_map[][2] = {
- { GC_HWIP, adev->gfx.xcc_mask },
- { SDMA0_HWIP, adev->sdma.sdma_mask },
- { VCN_HWIP, adev->vcn.inst_mask },
- };
- int i;
+ int i, j;
- for (i = 0; i < ARRAY_SIZE(ip_map); ++i)
- amdgpu_populate_ip_map(adev, ip_map[i][0], ip_map[i][1]);
-
- adev->ip_map.logical_to_dev_inst = amdgpu_logical_to_dev_inst;
- adev->ip_map.logical_to_dev_mask = amdgpu_logical_to_dev_mask;
+ /* Assume 'logical instance == physical instance' unless overridden. */
+ for (i = 0; i < MAX_HWIP; i++) {
+ for (j = 0; j < HWIP_MAX_INSTANCE; j++)
+ adev->ip_map.dev_inst[i][j] = j;
+ }
}
int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h
index 70fc4e5db51f..5dd6273982c4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h
@@ -90,13 +90,7 @@ struct amdgpu_fence;
struct amdgpu_ip_map_info {
/* Map of logical to actual dev instances/mask */
- uint32_t dev_inst[MAX_HWIP][HWIP_MAX_INSTANCE];
- int8_t (*logical_to_dev_inst)(struct amdgpu_device *adev,
- enum amd_hw_ip_block_type block,
- int8_t inst);
- uint32_t (*logical_to_dev_mask)(struct amdgpu_device *adev,
- enum amd_hw_ip_block_type block,
- uint32_t mask);
+ unsigned int dev_inst[MAX_HWIP][HWIP_MAX_INSTANCE];
};
#define AMDGPU_MAX_IP_NUM AMD_IP_BLOCK_TYPE_NUM
@@ -125,6 +119,18 @@ struct amdgpu_ip_block {
void amdgpu_ip_map_init(struct amdgpu_device *adev);
+u32 amdgpu_ip_map_logical_to_dev_mask(struct amdgpu_ip_map_info *ip_map,
+ enum amd_hw_ip_block_type block,
+ u32 mask);
+
+static inline unsigned int
+amdgpu_ip_map_logical_to_dev_inst(struct amdgpu_ip_map_info *ip_map,
+ enum amd_hw_ip_block_type block,
+ unsigned int inst)
+{
+ return ip_map->dev_inst[block][inst];
+}
+
int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block);
int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
index 44fe40f9e8df..57bd34981be0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
@@ -31,7 +31,7 @@
#define AMDGPU_PREAMBLE_IB_PRESENT (1 << 0)
/* bit set means preamble IB is first presented in belonging context */
#define AMDGPU_PREAMBLE_IB_PRESENT_FIRST (1 << 1)
-/* bit set means context switch occured */
+/* bit set means context switch occurred */
#define AMDGPU_HAVE_CTX_SWITCH (1 << 2)
/* bit set means IB is preempted */
#define AMDGPU_IB_PREEMPTED (1 << 3)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
index 208566ffe898..9887a4f99aed 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
@@ -25,6 +25,7 @@
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_jpeg.h"
#include "amdgpu_pm.h"
#include "soc15d.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index a676fccc466d..66eb2f34cc0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -27,6 +27,7 @@
#include <drm/drm_drv.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_psp.h"
#include "amdgpu_ucode.h"
#include "amdgpu_xgmi.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index 3f3aa44921ab..6b2b8acdbf9b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -3894,6 +3894,8 @@ void amdgpu_ras_resume(struct amdgpu_device *adev)
return;
}
+ amdgpu_ras_mgr_set_debug_mode(adev, false);
+
if (con->flags & AMDGPU_RAS_FLAG_INIT_BY_VBIOS) {
/* Set up all other IPs which are not implemented. There is a
* tricky thing that IP's actual ras error type should be
@@ -3954,9 +3956,6 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_telemetry_en(adev))
return 0;
- if (amdgpu_uniras_enabled(adev))
- amdgpu_ras_mgr_set_debug_mode(adev, false);
-
list_for_each_entry_safe(node, tmp, &adev->ras_list, node) {
obj = node->ras_obj;
if (!obj) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 686c92e96025..3aea81c75fdd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -117,22 +117,7 @@ int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned int ndw)
*/
void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
- uint32_t occupied, chunk1, chunk2;
-
- occupied = ring->wptr & ring->buf_mask;
- chunk1 = ring->buf_mask + 1 - occupied;
- chunk1 = (chunk1 >= count) ? count : chunk1;
- chunk2 = count - chunk1;
-
- if (chunk1)
- memset32(&ring->ring[occupied], ring->funcs->nop, chunk1);
-
- if (chunk2)
- memset32(ring->ring, ring->funcs->nop, chunk2);
-
- ring->wptr += count;
- ring->wptr &= ring->ptr_mask;
- ring->count_dw -= count;
+ amdgpu_ring_fill(ring, ring->funcs->nop, count);
}
/**
@@ -347,8 +332,6 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->buf_mask = (ring->ring_size / 4) - 1;
ring->ptr_mask = ring->funcs->support_64bit_ptrs ?
0xffffffffffffffff : ring->buf_mask;
- /* Initialize cached_rptr to 0 */
- ring->cached_rptr = 0;
if (!ring->ring_backup) {
ring->ring_backup = kvzalloc(ring->ring_size, GFP_KERNEL);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index 6b6ee4083c8d..b2040f80b7f2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -423,8 +423,6 @@ struct amdgpu_ring {
bool is_sw_ring;
unsigned int entry_index;
- /* store the cached rptr to restore after reset */
- uint64_t cached_rptr;
};
#define amdgpu_ring_parse_cs(r, p, job, ib) ((r)->funcs->parse_cs((p), (job), (ib)))
@@ -490,6 +488,25 @@ static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
memset32(ring->ring, ring->funcs->nop, ring->buf_mask + 1);
}
+static inline void amdgpu_ring_clear_ring_and_ptrs(struct amdgpu_ring *ring)
+{
+ /* Clear the contents of the ring. */
+ amdgpu_ring_clear_ring(ring);
+
+ /* Clear the ring pointers on the CPU. */
+ ring->wptr = 0;
+
+ /*
+ * Clear the ring pointers allocated in writeback.
+ *
+ * Note: we always allocate 64 bits for these pointers,
+ * but older HW generations only use the lower 32 bits.
+ * Use 64-bit atomics for simplicity.
+ */
+ atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
+ atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0);
+}
+
static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
{
ring->ring[ring->wptr++ & ring->buf_mask] = v;
@@ -522,6 +539,32 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
ring->count_dw -= count_dw;
}
+static inline void amdgpu_ring_fill(struct amdgpu_ring *ring,
+ u32 val, u32 count)
+{
+ const u32 buf_mask = ring->buf_mask;
+ u32 occupied, chunk1, chunk2;
+ u64 wptr = ring->wptr;
+
+ if (count == 0)
+ return;
+
+ occupied = wptr & buf_mask;
+ chunk1 = buf_mask + 1 - occupied;
+ chunk1 = (chunk1 >= count) ? count : chunk1;
+ chunk2 = count - chunk1;
+
+ if (chunk1)
+ memset32(&ring->ring[occupied], val, chunk1);
+
+ if (chunk2)
+ memset32(ring->ring, val, chunk2);
+
+ wptr += count;
+ ring->wptr = wptr & ring->ptr_mask;
+ ring->count_dw -= count;
+}
+
static inline unsigned int amdgpu_ring_get_dw_distance(struct amdgpu_ring *ring,
u64 start_wptr, u64 end_wptr)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
index fbac732f3e01..87ecbd429f95 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
@@ -22,6 +22,7 @@
*/
#include <linux/firmware.h>
+#include <linux/stdarg.h>
#include "amdgpu.h"
#include "amdgpu_sdma.h"
#include "amdgpu_ras.h"
@@ -37,57 +38,35 @@
* GPU SDMA IP block helpers function.
*/
-struct amdgpu_sdma_instance *amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring)
+int __printf(4, 5)
+amdgpu_sdma_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
+ unsigned int instance, const char *fmt, ...)
{
- struct amdgpu_device *adev = ring->adev;
- int i;
-
- for (i = 0; i < adev->sdma.num_instances; i++)
- if (ring == &adev->sdma.instance[i].ring ||
- ring == &adev->sdma.instance[i].page)
- return &adev->sdma.instance[i];
-
- return NULL;
-}
-
-int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index)
-{
- struct amdgpu_device *adev = ring->adev;
- int i;
-
- for (i = 0; i < adev->sdma.num_instances; i++) {
- if (ring == &adev->sdma.instance[i].ring ||
- ring == &adev->sdma.instance[i].page) {
- *index = i;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-uint64_t amdgpu_sdma_get_csa_mc_addr(struct amdgpu_ring *ring,
- unsigned int vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- uint64_t csa_mc_addr;
- uint32_t index = 0;
+ struct amdgpu_sdma_instance *sdma;
+ va_list args;
int r;
- /* don't enable OS preemption on SDMA under SRIOV */
- if (amdgpu_sriov_vf(adev) || vmid == 0 || !adev->gfx.mcbp)
- return 0;
+ ring->ring_obj = NULL;
- r = amdgpu_sdma_get_index_from_ring(ring, &index);
+ va_start(args, fmt);
+ vsnprintf(ring->name, sizeof(ring->name), fmt, args);
+ va_end(args);
+
+ r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
+ AMDGPU_SDMA_IRQ_INSTANCE0 + instance,
+ AMDGPU_RING_PRIO_DEFAULT, NULL);
+ if (r)
+ return r;
- if (r || index > 31)
- csa_mc_addr = 0;
+ sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ if (amdgpu_sriov_vf(adev) || !adev->gfx.mcbp)
+ sdma->csa_addr = 0;
else
- csa_mc_addr = amdgpu_csa_vaddr(adev) +
- AMDGPU_CSA_SDMA_OFFSET +
- index * AMDGPU_CSA_SDMA_SIZE;
+ sdma->csa_addr = amdgpu_csa_vaddr(adev) +
+ AMDGPU_CSA_SDMA_OFFSET +
+ ring->me * AMDGPU_CSA_SDMA_SIZE;
- return csa_mc_addr;
+ return r;
}
int amdgpu_sdma_ras_late_init(struct amdgpu_device *adev,
@@ -542,16 +521,14 @@ static int amdgpu_sdma_soft_reset(struct amdgpu_device *adev, u32 instance_id)
}
/**
- * amdgpu_sdma_reset_engine - Reset a specific SDMA engine
+ * amdgpu_sdma_reset_engine() - Reset a specific SDMA engine instance.
+ *
* @adev: Pointer to the AMDGPU device
* @instance_id: Logical ID of the SDMA engine instance to reset
- * @caller_handles_kernel_queues: Skip kernel queue processing. Caller
- * will handle it.
*
* Returns: 0 on success, or a negative error code on failure.
*/
-int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
- bool caller_handles_kernel_queues)
+int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id)
{
struct amdgpu_sdma_instance *sdma_instance = &adev->sdma.instance[instance_id];
struct amdgpu_ring *gfx_ring = &sdma_instance->ring;
@@ -564,20 +541,23 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
mutex_lock(&sdma_instance->engine_reset_mutex);
- if (!caller_handles_kernel_queues) {
- /* Stop the scheduler's work queue for the GFX and page rings if they are running.
- * This ensures that no new tasks are submitted to the queues while
- * the reset is in progress.
- */
+ /*
+ * Stop the scheduler's work queue for the GFX and page rings if they are running.
+ * This ensures that no new tasks are submitted to the queues while
+ * the reset is in progress.
+ */
+ if (amdgpu_ring_sched_ready(gfx_ring) && !drm_sched_is_stopped(&gfx_ring->sched))
drm_sched_wqueue_stop(&gfx_ring->sched);
- gfx_fence = amdgpu_ring_find_guilty_fence(gfx_ring);
- amdgpu_ring_reset_helper_begin(gfx_ring, gfx_fence);
- if (adev->sdma.has_page_queue) {
+ gfx_fence = amdgpu_ring_find_guilty_fence(gfx_ring);
+ amdgpu_ring_reset_helper_begin(gfx_ring, gfx_fence);
+
+ if (adev->sdma.has_page_queue) {
+ if (amdgpu_ring_sched_ready(page_ring) && !drm_sched_is_stopped(&page_ring->sched))
drm_sched_wqueue_stop(&page_ring->sched);
- page_fence = amdgpu_ring_find_guilty_fence(page_ring);
- amdgpu_ring_reset_helper_begin(page_ring, page_fence);
- }
+
+ page_fence = amdgpu_ring_find_guilty_fence(page_ring);
+ amdgpu_ring_reset_helper_begin(page_ring, page_fence);
}
if (sdma_instance->funcs->stop_kernel_queue) {
@@ -593,6 +573,11 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
goto exit;
}
+ amdgpu_ring_clear_ring_and_ptrs(gfx_ring);
+
+ if (adev->sdma.has_page_queue)
+ amdgpu_ring_clear_ring_and_ptrs(page_ring);
+
if (sdma_instance->funcs->start_kernel_queue) {
sdma_instance->funcs->start_kernel_queue(gfx_ring);
if (adev->sdma.has_page_queue)
@@ -600,22 +585,25 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
}
exit:
- if (!caller_handles_kernel_queues) {
- /* Restart the scheduler's work queue for the GFX and page rings
- * if they were stopped by this function. This allows new tasks
- * to be submitted to the queues after the reset is complete.
- */
- if (!ret) {
- ret = amdgpu_ring_reset_helper_end(gfx_ring, gfx_fence);
+ /* Restart the scheduler's work queue for the GFX and page rings
+ * if they were stopped by this function. This allows new tasks
+ * to be submitted to the queues after the reset is complete.
+ */
+ if (!ret) {
+ ret = amdgpu_ring_reset_helper_end(gfx_ring, gfx_fence);
+ if (ret)
+ goto unlock;
+
+ if (amdgpu_ring_sched_ready(gfx_ring))
+ drm_sched_wqueue_start(&gfx_ring->sched);
+
+ if (adev->sdma.has_page_queue) {
+ ret = amdgpu_ring_reset_helper_end(page_ring, page_fence);
if (ret)
goto unlock;
- drm_sched_wqueue_start(&gfx_ring->sched);
- if (adev->sdma.has_page_queue) {
- ret = amdgpu_ring_reset_helper_end(page_ring, page_fence);
- if (ret)
- goto unlock;
+
+ if (amdgpu_ring_sched_ready(page_ring))
drm_sched_wqueue_start(&page_ring->sched);
- }
}
}
unlock:
@@ -623,3 +611,38 @@ unlock:
return ret;
}
+
+/**
+ * amdgpu_sdma_reset_queue_legacy() - Reset legacy SDMA queue after timeout (without MES)
+ *
+ * @ring: Pointer to the ring of the SDMA queue
+ * @vmid: VMID of the timed out job
+ * @timedout_fence: Fence of the timed out job
+ *
+ * Common implementation for resetting SDMA queues without MES (legacy).
+ * This relies on the proper amdgpu_sdma_funcs to be set up
+ * for the given ring.
+ *
+ * Applicable to SDMA versions that don't rely on the MES yet,
+ * that is all versions up to SDMA v5.x and older.
+ */
+int amdgpu_sdma_reset_queue_legacy(struct amdgpu_ring *ring,
+ unsigned int vmid,
+ struct amdgpu_fence *timedout_fence)
+{
+ struct amdgpu_device *adev = ring->adev;
+ int r;
+
+ if (ring->me >= adev->sdma.num_instances) {
+ dev_err(adev->dev, "sdma instance not found\n");
+ return -EINVAL;
+ }
+
+ amdgpu_amdkfd_suspend(adev, true);
+ r = amdgpu_sdma_reset_engine(adev, ring->me);
+ amdgpu_amdkfd_resume(adev, true);
+ if (r)
+ return r;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
index 659836c2c377..51dc52757f48 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
@@ -23,153 +23,49 @@
#ifndef __AMDGPU_SDMA_H__
#define __AMDGPU_SDMA_H__
-#include "amdgpu_ras.h"
-/* max number of IP instances */
-#define AMDGPU_MAX_SDMA_INSTANCES 16
+#include "amdgpu_sdma_types.h"
+#include "amdgpu.h"
+#include "amdgpu_ring.h"
-enum amdgpu_sdma_irq {
- AMDGPU_SDMA_IRQ_INSTANCE0 = 0,
- AMDGPU_SDMA_IRQ_INSTANCE1,
- AMDGPU_SDMA_IRQ_INSTANCE2,
- AMDGPU_SDMA_IRQ_INSTANCE3,
- AMDGPU_SDMA_IRQ_INSTANCE4,
- AMDGPU_SDMA_IRQ_INSTANCE5,
- AMDGPU_SDMA_IRQ_INSTANCE6,
- AMDGPU_SDMA_IRQ_INSTANCE7,
- AMDGPU_SDMA_IRQ_INSTANCE8,
- AMDGPU_SDMA_IRQ_INSTANCE9,
- AMDGPU_SDMA_IRQ_INSTANCE10,
- AMDGPU_SDMA_IRQ_INSTANCE11,
- AMDGPU_SDMA_IRQ_INSTANCE12,
- AMDGPU_SDMA_IRQ_INSTANCE13,
- AMDGPU_SDMA_IRQ_INSTANCE14,
- AMDGPU_SDMA_IRQ_INSTANCE15,
- AMDGPU_SDMA_IRQ_LAST
-};
+#include <linux/types.h>
-#define NUM_SDMA(x) hweight32(x)
-
-struct amdgpu_sdma_csa_info {
- u32 size;
- u32 alignment;
-};
-
-struct amdgpu_sdma_funcs {
- int (*stop_kernel_queue)(struct amdgpu_ring *ring);
- int (*start_kernel_queue)(struct amdgpu_ring *ring);
- int (*soft_reset_kernel_queue)(struct amdgpu_device *adev, u32 instance_id);
- bool (*detect_hung_queue)(struct amdgpu_device *adev, u32 doorbell_index,
- u32 *instance_id, u32 *queue_id);
-};
-
-struct amdgpu_sdma_instance {
- /* SDMA firmware */
- const struct firmware *fw;
- uint32_t fw_version;
- uint32_t feature_version;
-
- struct amdgpu_ring ring;
- struct amdgpu_ring page;
- bool burst_nop;
- union {
- uint32_t aid_id;
- uint32_t xcc_id;
- };
-
- struct amdgpu_bo *sdma_fw_obj;
- uint64_t sdma_fw_gpu_addr;
- uint32_t *sdma_fw_ptr;
- struct mutex engine_reset_mutex;
- /* track guilty state of GFX and PAGE queues */
- bool gfx_guilty;
- bool page_guilty;
- const struct amdgpu_sdma_funcs *funcs;
-};
-
-struct amdgpu_sdma_ras {
- struct amdgpu_ras_block_object ras_block;
-};
-
-struct amdgpu_sdma {
- struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES];
- struct amdgpu_irq_src trap_irq;
- struct amdgpu_irq_src illegal_inst_irq;
- struct amdgpu_irq_src fence_irq;
- struct amdgpu_irq_src ecc_irq;
- struct amdgpu_irq_src vm_hole_irq;
- struct amdgpu_irq_src doorbell_invalid_irq;
- struct amdgpu_irq_src pool_timeout_irq;
- struct amdgpu_irq_src srbm_write_irq;
- struct amdgpu_irq_src ctxt_empty_irq;
+struct amdgpu_device;
+struct amdgpu_iv_entry;
+struct amdgpu_irq_src;
+struct amdgpu_ring;
+struct ras_common_if;
- int num_instances;
- uint32_t sdma_mask;
- bool sdma_debug;
- union {
- int num_inst_per_aid;
- int num_inst_per_xcc;
- };
- uint32_t srbm_soft_reset;
- bool has_page_queue;
- struct ras_common_if *ras_if;
- struct amdgpu_sdma_ras *ras;
- uint32_t *ip_dump;
- uint32_t supported_reset;
- struct list_head reset_callback_list;
- bool no_user_submission;
- bool disable_uq;
- void (*get_csa_info)(struct amdgpu_device *adev,
- struct amdgpu_sdma_csa_info *csa_info);
-};
-
-/*
- * Provided by hw blocks that can move/clear data. e.g., gfx or sdma
- * But currently, we use sdma to move data.
- */
-struct amdgpu_buffer_funcs {
- /* maximum bytes in a single operation */
- uint32_t copy_max_bytes;
-
- /* number of dw to reserve per operation */
- unsigned copy_num_dw;
-
- /* used for buffer migration */
- void (*emit_copy_buffer)(struct amdgpu_ib *ib,
- /* src addr in bytes */
- uint64_t src_offset,
- /* dst addr in bytes */
- uint64_t dst_offset,
- /* number of byte to transfer */
- uint32_t byte_count,
- uint32_t copy_flags);
-
- /* maximum bytes in a single operation */
- uint32_t fill_max_bytes;
+#define NUM_SDMA(x) hweight32(x)
- /* number of dw to reserve per operation */
- unsigned fill_num_dw;
+int __printf(4, 5)
+amdgpu_sdma_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
+ unsigned int instance, const char *fmt, ...);
- /* used for buffer clearing */
- void (*emit_fill_buffer)(struct amdgpu_ib *ib,
- /* value to write to memory */
- uint32_t src_data,
- /* dst addr in bytes */
- uint64_t dst_offset,
- /* number of byte to fill */
- uint32_t byte_count);
-};
+int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id);
-int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
- bool caller_handles_kernel_queues);
+int amdgpu_sdma_reset_queue_legacy(struct amdgpu_ring *ring,
+ unsigned int vmid,
+ struct amdgpu_fence *timedout_fence);
#define amdgpu_emit_copy_buffer(adev, ib, s, d, b, t) (adev)->mman.buffer_funcs->emit_copy_buffer((ib), (s), (d), (b), (t))
#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
-struct amdgpu_sdma_instance *
-amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring);
-int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index);
-uint64_t amdgpu_sdma_get_csa_mc_addr(struct amdgpu_ring *ring, unsigned vmid);
+static inline struct amdgpu_sdma_instance *
+amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring)
+{
+ return &ring->adev->sdma.instance[ring->me];
+}
+
+static inline uint64_t
+amdgpu_sdma_get_csa_mc_addr(struct amdgpu_ring *ring, unsigned vmid)
+{
+ if (vmid == 0)
+ return 0;
+ else
+ return amdgpu_sdma_get_instance_from_ring(ring)->csa_addr;
+}
+
int amdgpu_sdma_ras_late_init(struct amdgpu_device *adev,
struct ras_common_if *ras_block);
int amdgpu_sdma_process_ras_data_cb(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma_types.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma_types.h
new file mode 100644
index 000000000000..1360db74d8b7
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma_types.h
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __AMDGPU_SDMA_TYPES_H__
+#define __AMDGPU_SDMA_TYPES_H__
+#include "amdgpu_ras.h"
+
+/* max number of IP instances */
+#define AMDGPU_MAX_SDMA_INSTANCES 16
+
+enum amdgpu_sdma_irq {
+ AMDGPU_SDMA_IRQ_INSTANCE0 = 0,
+ AMDGPU_SDMA_IRQ_INSTANCE1,
+ AMDGPU_SDMA_IRQ_INSTANCE2,
+ AMDGPU_SDMA_IRQ_INSTANCE3,
+ AMDGPU_SDMA_IRQ_INSTANCE4,
+ AMDGPU_SDMA_IRQ_INSTANCE5,
+ AMDGPU_SDMA_IRQ_INSTANCE6,
+ AMDGPU_SDMA_IRQ_INSTANCE7,
+ AMDGPU_SDMA_IRQ_INSTANCE8,
+ AMDGPU_SDMA_IRQ_INSTANCE9,
+ AMDGPU_SDMA_IRQ_INSTANCE10,
+ AMDGPU_SDMA_IRQ_INSTANCE11,
+ AMDGPU_SDMA_IRQ_INSTANCE12,
+ AMDGPU_SDMA_IRQ_INSTANCE13,
+ AMDGPU_SDMA_IRQ_INSTANCE14,
+ AMDGPU_SDMA_IRQ_INSTANCE15,
+ AMDGPU_SDMA_IRQ_LAST
+};
+
+struct amdgpu_sdma_csa_info {
+ u32 size;
+ u32 alignment;
+};
+
+struct amdgpu_sdma_funcs {
+ int (*stop_kernel_queue)(struct amdgpu_ring *ring);
+ int (*start_kernel_queue)(struct amdgpu_ring *ring);
+ int (*soft_reset_kernel_queue)(struct amdgpu_device *adev, u32 instance_id);
+ bool (*detect_hung_queue)(struct amdgpu_device *adev, u32 doorbell_index,
+ u32 *instance_id, u32 *queue_id);
+};
+
+struct amdgpu_sdma_instance {
+ /* SDMA firmware */
+ const struct firmware *fw;
+ uint32_t fw_version;
+ uint32_t feature_version;
+
+ struct amdgpu_ring ring;
+ struct amdgpu_ring page;
+ bool burst_nop;
+ union {
+ uint32_t aid_id;
+ uint32_t xcc_id;
+ };
+
+ uint64_t csa_addr;
+
+ struct amdgpu_bo *sdma_fw_obj;
+ uint64_t sdma_fw_gpu_addr;
+ uint32_t *sdma_fw_ptr;
+ struct mutex engine_reset_mutex;
+ /* track guilty state of GFX and PAGE queues */
+ bool gfx_guilty;
+ bool page_guilty;
+ const struct amdgpu_sdma_funcs *funcs;
+};
+
+struct amdgpu_sdma_ras {
+ struct amdgpu_ras_block_object ras_block;
+};
+
+struct amdgpu_sdma {
+ struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES];
+ struct amdgpu_irq_src trap_irq;
+ struct amdgpu_irq_src illegal_inst_irq;
+ struct amdgpu_irq_src fence_irq;
+ struct amdgpu_irq_src ecc_irq;
+ struct amdgpu_irq_src vm_hole_irq;
+ struct amdgpu_irq_src doorbell_invalid_irq;
+ struct amdgpu_irq_src pool_timeout_irq;
+ struct amdgpu_irq_src srbm_write_irq;
+ struct amdgpu_irq_src ctxt_empty_irq;
+
+ int num_instances;
+ uint32_t sdma_mask;
+ bool sdma_debug;
+ union {
+ int num_inst_per_aid;
+ int num_inst_per_xcc;
+ };
+ uint32_t srbm_soft_reset;
+ bool has_page_queue;
+ struct ras_common_if *ras_if;
+ struct amdgpu_sdma_ras *ras;
+ uint32_t *ip_dump;
+ uint32_t supported_reset;
+ struct list_head reset_callback_list;
+ bool no_user_submission;
+ bool disable_uq;
+ void (*get_csa_info)(struct amdgpu_device *adev,
+ struct amdgpu_sdma_csa_info *csa_info);
+};
+
+/*
+ * Provided by hw blocks that can move/clear data. e.g., gfx or sdma
+ * But currently, we use sdma to move data.
+ */
+struct amdgpu_buffer_funcs {
+ /* maximum bytes in a single operation */
+ uint32_t copy_max_bytes;
+
+ /* number of dw to reserve per operation */
+ unsigned copy_num_dw;
+
+ /* used for buffer migration */
+ void (*emit_copy_buffer)(struct amdgpu_ib *ib,
+ /* src addr in bytes */
+ uint64_t src_offset,
+ /* dst addr in bytes */
+ uint64_t dst_offset,
+ /* number of byte to transfer */
+ uint32_t byte_count,
+ uint32_t copy_flags);
+
+ /* maximum bytes in a single operation */
+ uint32_t fill_max_bytes;
+
+ /* number of dw to reserve per operation */
+ unsigned fill_num_dw;
+
+ /* used for buffer clearing */
+ void (*emit_fill_buffer)(struct amdgpu_ib *ib,
+ /* value to write to memory */
+ uint32_t src_data,
+ /* dst addr in bytes */
+ uint64_t dst_offset,
+ /* number of byte to fill */
+ uint32_t byte_count);
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 09dd3174d505..66f4a1872913 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -730,6 +730,39 @@ TRACE_EVENT(amdgpu_userq_state_changed,
__entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->to)
);
+TRACE_EVENT(amdgpu_register_pid,
+ TP_PROTO(uint32_t pid, int major, int minor),
+ TP_ARGS(pid, major, minor),
+ TP_STRUCT__entry(
+ __field(u32, pid)
+ __field(int, major)
+ __field(int, minor)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->major = major;
+ __entry->minor = minor;
+ ),
+ TP_printk("amdgpu register pid %d render %d:%d",
+ __entry->pid, __entry->major, __entry->minor)
+);
+TRACE_EVENT(amdgpu_deregister_pid,
+ TP_PROTO(uint32_t pid, int major, int minor),
+ TP_ARGS(pid, major, minor),
+ TP_STRUCT__entry(
+ __field(u32, pid)
+ __field(int, major)
+ __field(int, minor)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->major = major;
+ __entry->minor = minor;
+ ),
+ TP_printk("amdgpu deregister pid %d render %d:%d",
+ __entry->pid, __entry->major, __entry->minor)
+);
+
#undef AMDGPU_JOB_GET_TIMELINE_NAME
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index ab564202f550..b2c2650b0149 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -26,6 +26,7 @@
#include <drm/drm_mm.h>
#include <linux/random.h>
#include "amdgpu.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_ualink.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_dma_buf.h"
@@ -2270,11 +2271,9 @@ static void amdgpu_ualink_process_hello_msg(struct amdgpu_device *adev,
/* otherwise, leave it IN_PROGRESS to signal the completion below */
mutex_unlock(&conn_state->lock);
} else {
- /* Set the connection state back to In Progress and revoke
- * all exports and release all imports corresponding to the
- * sender GPU.
+ /* Leave state ESTABLISHED so handle_connection_reset()
+ * performs the transition and imp/exp XA cleanup.
*/
- conn_state->state = AMDGPU_UALINK_CONN_PENDING;
generation_count = conn_state->generation_count;
mutex_unlock(&conn_state->lock);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 3938f7b8ec4b..12fbff02e4b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -1043,7 +1043,11 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr)
retry_lock:
drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
drm_exec_until_all_locked(&exec) {
- ret = amdgpu_vm_lock_pd(vm, &exec, 1);
+ /*
+ * Rearm adds one BOOKKEEP fence and validation may queue move fences
+ * on the root PD BO, so reserve caller-side slots accordingly.
+ */
+ ret = amdgpu_vm_lock_pd(vm, &exec, TTM_NUM_MOVE_FENCES + 1);
drm_exec_retry_on_contention(&exec);
if (unlikely(ret))
goto unlock_all;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 36f6dcd063fe..6b210f7af57b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -33,6 +33,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
+#include <drm/drm_ioctl.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/drm_exec.h>
#include "amdgpu.h"
@@ -2563,6 +2564,12 @@ static int amdgpu_vm_create_task_info(struct amdgpu_vm *vm)
return 0;
}
+static void amdgpu_vm_render_devt(struct amdgpu_device *adev, int *major, int *minor)
+{
+ *major = DRM_MAJOR;
+ *minor = adev_to_drm(adev)->render->index;
+}
+
/**
* amdgpu_vm_set_task_info - Sets VMs task info.
*
@@ -2576,6 +2583,18 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm)
if (vm->task_info->task.pid == current->pid)
return;
+ if (vm->root.bo) {
+ struct amdgpu_device *adev = amdgpu_ttm_adev(vm->root.bo->tbo.bdev);
+ int major, minor;
+
+ amdgpu_vm_render_devt(adev, &major, &minor);
+
+ if (vm->task_info->task.pid)
+ trace_amdgpu_deregister_pid(vm->task_info->task.pid,
+ major, minor);
+ trace_amdgpu_register_pid(current->pid, major, minor);
+ }
+
vm->task_info->task.pid = current->pid;
get_task_comm(vm->task_info->task.comm, current);
@@ -2876,6 +2895,13 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
ti->process_name, ti->task.pid, ti->task.comm, ti->tgid);
}
+ if (vm->task_info && vm->task_info->task.pid) {
+ int major, minor;
+
+ amdgpu_vm_render_devt(adev, &major, &minor);
+ trace_amdgpu_deregister_pid(vm->task_info->task.pid, major, minor);
+ }
+
amdgpu_vm_put_task_info(vm->task_info);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
index c80ffa08920d..ab14079d1c42 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
@@ -23,6 +23,7 @@
#include "amdgpu.h"
#include "amdgpu_xcp.h"
#include "amdgpu_drv.h"
+#include "amdgpu_ip.h"
#include <drm/drm_drv.h>
#include "../amdxcp/amdgpu_xcp_drv.h"
@@ -694,14 +695,16 @@ void amdgpu_xcp_update_supported_modes(struct amdgpu_xcp_mgr *xcp_mgr)
int amdgpu_xcp_pre_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags)
{
+ int ret = 0;
+
/* TODO:
* Stop user queues and threads, and make sure GPU is empty of work.
*/
if (flags & AMDGPU_XCP_OPS_KFD)
- amdgpu_amdkfd_device_fini_sw(xcp_mgr->adev);
+ ret = amdgpu_amdkfd_prepare_partition_switch(xcp_mgr->adev);
- return 0;
+ return ret;
}
int amdgpu_xcp_post_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags)
diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
index cddfe4015f53..05e4edf72e4d 100644
--- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
+++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
@@ -30,6 +30,7 @@
#include "gfxhub_v1_2.h"
#include "sdma_v4_4_2.h"
#include "amdgpu_ip.h"
+#include "amdgpu_sdma.h"
void aqua_vanjaram_doorbell_index_init(struct amdgpu_device *adev)
{
@@ -391,15 +392,9 @@ static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
!adev->in_suspend)
flags |= AMDGPU_XCP_OPS_KFD;
- if (flags & AMDGPU_XCP_OPS_KFD) {
- ret = amdgpu_amdkfd_check_and_lock_kfd(adev);
- if (ret)
- goto out;
- }
-
ret = amdgpu_xcp_pre_partition_switch(xcp_mgr, flags);
if (ret)
- goto unlock;
+ goto out;
num_xcc_per_xcp = __aqua_vanjaram_get_xcc_per_xcp(xcp_mgr, mode);
if (adev->gfx.funcs->switch_partition_mode)
@@ -413,9 +408,6 @@ static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
ret = amdgpu_xcp_post_partition_switch(xcp_mgr, flags);
if (!ret)
__aqua_vanjaram_update_available_partition_mode(xcp_mgr);
-unlock:
- if (flags & AMDGPU_XCP_OPS_KFD)
- amdgpu_amdkfd_unlock_kfd(adev);
out:
return ret;
}
@@ -513,6 +505,34 @@ static int aqua_vanjaram_xcp_mgr_init(struct amdgpu_device *adev)
return ret;
}
+static void amdgpu_populate_ip_map(struct amdgpu_device *adev,
+ enum amd_hw_ip_block_type ip_block,
+ uint32_t inst_mask)
+{
+ int l = 0, i;
+
+ while (inst_mask) {
+ i = ffs(inst_mask) - 1;
+ adev->ip_map.dev_inst[ip_block][l++] = i;
+ inst_mask &= ~(1 << i);
+ }
+ for (; l < HWIP_MAX_INSTANCE; l++)
+ adev->ip_map.dev_inst[ip_block][l] = -1;
+}
+
+static void amdgpu_ip_map_aqua_vanjaram_override(struct amdgpu_device *adev)
+{
+ u32 ip_map[][2] = {
+ { GC_HWIP, adev->gfx.xcc_mask },
+ { SDMA0_HWIP, adev->sdma.sdma_mask },
+ { VCN_HWIP, adev->vcn.inst_mask },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ip_map); ++i)
+ amdgpu_populate_ip_map(adev, ip_map[i][0], ip_map[i][1]);
+}
+
int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev)
{
u32 mask, avail_inst, inst_mask = adev->sdma.sdma_mask;
@@ -547,7 +567,7 @@ int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev)
if (ret)
return ret;
- amdgpu_ip_map_init(adev);
+ amdgpu_ip_map_aqua_vanjaram_override(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c
index e0e585f280e2..1a599d5cf6a5 100644
--- a/drivers/gpu/drm/amd/amdgpu/atom.c
+++ b/drivers/gpu/drm/amd/amdgpu/atom.c
@@ -1420,6 +1420,11 @@ static void atom_get_vbios_date(struct atom_context *ctx)
p_rom = ctx->bios;
+ if (ctx->bios_size < OFFSET_TO_VBIOS_DATE + 14) {
+ ctx->date[0] = '\0';
+ return;
+ }
+
date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE;
ctx->date[0] = '2';
@@ -1483,10 +1488,15 @@ static void atom_get_vbios_pn(struct atom_context *ctx)
vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER;
}
- if (*vbios_str == 0) {
+ if (vbios_str >= p_rom + ctx->bios_size)
+ vbios_str = NULL;
+
+ if (vbios_str == NULL || *vbios_str == 0) {
vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64);
if (vbios_str == NULL)
vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1;
+ if (vbios_str >= p_rom + ctx->bios_size)
+ vbios_str = NULL;
}
OPTIMIZER_HIDE_VAR(vbios_str);
if (vbios_str != NULL && *vbios_str == 0)
@@ -1494,7 +1504,9 @@ static void atom_get_vbios_pn(struct atom_context *ctx)
if (vbios_str != NULL) {
count = 0;
- while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' &&
+ while ((count < BIOS_STRING_LENGTH) &&
+ vbios_str + count < p_rom + ctx->bios_size &&
+ vbios_str[count] >= ' ' &&
vbios_str[count] <= 'z') {
ctx->vbios_pn[count] = vbios_str[count];
count++;
@@ -1527,9 +1539,10 @@ static void atom_get_vbios_version(struct atom_context *ctx)
/* find anchor ATOMBIOSBK-AMD */
vbios_ver =
atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, start, end, 64);
- if (vbios_ver != NULL) {
- /* skip ATOMBIOSBK-AMD VER */
- vbios_ver += 18;
+ if (vbios_ver != NULL)
+ vbios_ver += 18; /* skip ATOMBIOSBK-AMD VER */
+
+ if (vbios_ver != NULL && vbios_ver + STRLEN_NORMAL <= p_rom + ctx->bios_size) {
memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL);
} else {
ctx->vbios_ver_str[0] = '\0';
@@ -1545,7 +1558,13 @@ static void atom_get_vbios_build(struct atom_context *ctx)
base = CU16(ATOM_ROM_TABLE_PTR);
atom_rom_hdr = CSTR(base);
+ if ((uint32_t)base + ATOM_ROM_CFG_PTR + sizeof(uint16_t) > ctx->bios_size)
+ return;
+
str = CSTR(CU16(base + ATOM_ROM_CFG_PTR));
+ if (str >= atom_rom_hdr)
+ return;
+
/* Skip config string */
while (str < atom_rom_hdr && *str++)
;
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index de2323e23566..8a09fa912931 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -27,6 +27,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "cikd.h"
#include "cik.h"
@@ -55,8 +56,6 @@ static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev);
static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev);
static int cik_sdma_soft_reset(struct amdgpu_ip_block *ip_block);
-u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev);
-
MODULE_FIRMWARE("amdgpu/bonaire_sdma.bin");
MODULE_FIRMWARE("amdgpu/bonaire_sdma1.bin");
MODULE_FIRMWARE("amdgpu/hawaii_sdma.bin");
@@ -319,18 +318,6 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev)
}
/**
- * cik_sdma_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues (CIK).
- */
-static void cik_sdma_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* cik_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -402,7 +389,6 @@ static void cik_sdma_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
cik_sdma_gfx_stop(adev);
- cik_sdma_rlc_stop(adev);
}
for (i = 0; i < adev->sdma.num_instances; i++) {
@@ -504,20 +490,6 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev)
}
/**
- * cik_sdma_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them (CIK).
- * Returns 0 for success, error for failure.
- */
-static int cik_sdma_rlc_resume(struct amdgpu_device *adev)
-{
- /* XXX todo */
- return 0;
-}
-
-/**
* cik_sdma_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -581,9 +553,6 @@ static int cik_sdma_start(struct amdgpu_device *adev)
r = cik_sdma_gfx_resume(adev);
if (r)
return r;
- r = cik_sdma_rlc_resume(adev);
- if (r)
- return r;
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
index f812d6d81e9c..d7effa43c0fa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
@@ -203,12 +203,7 @@ static int gfx_v12_1_get_cu_info(struct amdgpu_device *adev,
static uint64_t gfx_v12_1_get_gpu_clock_counter(struct amdgpu_device *adev);
static void gfx_v12_1_xcc_select_se_sh(struct amdgpu_device *adev, u32 se_num,
u32 sh_num, u32 instance, int xcc_id);
-static void gfx_v12_1_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg,
- uint32_t val);
static int gfx_v12_1_wait_for_rlc_autoload_complete(struct amdgpu_device *adev);
-static void gfx_v12_1_ring_invalidate_tlbs(struct amdgpu_ring *ring,
- uint16_t pasid, uint32_t flush_type,
- bool all_hub, uint8_t dst_sel);
static void gfx_v12_1_xcc_set_safe_mode(struct amdgpu_device *adev, int xcc_id);
static void gfx_v12_1_xcc_unset_safe_mode(struct amdgpu_device *adev, int xcc_id);
static void gfx_v12_1_update_perf_clk(struct amdgpu_device *adev,
@@ -219,142 +214,6 @@ static int gfx_v12_1_init_cp_compute_microcode_bo(struct amdgpu_device *adev);
static void gfx_v12_1_xcc_update_medium_grain_clock_gating(
struct amdgpu_device *adev, bool enable, int xcc_id, bool force);
-static void gfx_v12_1_kiq_set_resources(struct amdgpu_ring *kiq_ring,
- uint64_t queue_mask)
-{
- amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_SET_RESOURCES, 6));
- amdgpu_ring_write(kiq_ring, PACKET3_SET_RESOURCES_VMID_MASK(0) |
- PACKET3_SET_RESOURCES_QUEUE_TYPE(0)); /* vmid_mask:0 queue_type:0 (KIQ) */
- amdgpu_ring_write(kiq_ring, lower_32_bits(queue_mask)); /* queue mask lo */
- amdgpu_ring_write(kiq_ring, upper_32_bits(queue_mask)); /* queue mask hi */
- amdgpu_ring_write(kiq_ring, 0); /* gws mask lo */
- amdgpu_ring_write(kiq_ring, 0); /* gws mask hi */
- amdgpu_ring_write(kiq_ring, 0); /* oac mask */
- amdgpu_ring_write(kiq_ring, 0);
-}
-
-static void gfx_v12_1_kiq_map_queues(struct amdgpu_ring *kiq_ring,
- struct amdgpu_ring *ring)
-{
- uint64_t mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj);
- uint64_t wptr_addr = ring->wptr_gpu_addr;
- uint32_t me = 0, eng_sel = 0;
-
- switch (ring->funcs->type) {
- case AMDGPU_RING_TYPE_COMPUTE:
- me = 1;
- eng_sel = 0;
- break;
- case AMDGPU_RING_TYPE_MES:
- me = 2;
- eng_sel = 5;
- break;
- default:
- WARN_ON(1);
- }
-
- amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_MAP_QUEUES, 5));
- /* Q_sel:0, vmid:0, vidmem: 1, engine:0, num_Q:1*/
- amdgpu_ring_write(kiq_ring, /* Q_sel: 0, vmid: 0, engine: 0, num_Q: 1 */
- PACKET3_MAP_QUEUES_QUEUE_SEL(0) | /* Queue_Sel */
- PACKET3_MAP_QUEUES_VMID(0) | /* VMID */
- PACKET3_MAP_QUEUES_QUEUE(ring->queue) |
- PACKET3_MAP_QUEUES_PIPE(ring->pipe) |
- PACKET3_MAP_QUEUES_ME((me)) |
- PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */
- PACKET3_MAP_QUEUES_ENGINE_SEL(eng_sel) |
- PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */
- amdgpu_ring_write(kiq_ring, PACKET3_MAP_QUEUES_DOORBELL_OFFSET(ring->doorbell_index));
- amdgpu_ring_write(kiq_ring, lower_32_bits(mqd_addr));
- amdgpu_ring_write(kiq_ring, upper_32_bits(mqd_addr));
- amdgpu_ring_write(kiq_ring, lower_32_bits(wptr_addr));
- amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
-}
-
-static void gfx_v12_1_kiq_unmap_queues(struct amdgpu_ring *kiq_ring,
- struct amdgpu_ring *ring,
- enum amdgpu_unmap_queues_action action,
- u64 gpu_addr, u64 seq)
-{
- struct amdgpu_device *adev = kiq_ring->adev;
- uint32_t eng_sel = ring->funcs->type == AMDGPU_RING_TYPE_GFX ? 4 : 0;
-
- if (adev->enable_mes && !adev->gfx.kiq[0].ring.sched.ready) {
- amdgpu_mes_unmap_legacy_queue(adev, ring, action, gpu_addr,
- seq, kiq_ring->xcc_id);
- return;
- }
-
- amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_UNMAP_QUEUES, 4));
- amdgpu_ring_write(kiq_ring, /* Q_sel: 0, vmid: 0, engine: 0, num_Q: 1 */
- PACKET3_UNMAP_QUEUES_ACTION(action) |
- PACKET3_UNMAP_QUEUES_QUEUE_SEL(0) |
- PACKET3_UNMAP_QUEUES_ENGINE_SEL(eng_sel) |
- PACKET3_UNMAP_QUEUES_NUM_QUEUES(1));
- amdgpu_ring_write(kiq_ring,
- PACKET3_UNMAP_QUEUES_DOORBELL_OFFSET0(ring->doorbell_index));
-
- if (action == PREEMPT_QUEUES_NO_UNMAP) {
- amdgpu_ring_write(kiq_ring, lower_32_bits(gpu_addr));
- amdgpu_ring_write(kiq_ring, upper_32_bits(gpu_addr));
- amdgpu_ring_write(kiq_ring, seq);
- } else {
- amdgpu_ring_write(kiq_ring, 0);
- amdgpu_ring_write(kiq_ring, 0);
- amdgpu_ring_write(kiq_ring, 0);
- }
-}
-
-static void gfx_v12_1_kiq_query_status(struct amdgpu_ring *kiq_ring,
- struct amdgpu_ring *ring,
- u64 addr, u64 seq)
-{
- uint32_t eng_sel = ring->funcs->type == AMDGPU_RING_TYPE_GFX ? 4 : 0;
-
- amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_QUERY_STATUS, 5));
- amdgpu_ring_write(kiq_ring,
- PACKET3_QUERY_STATUS_CONTEXT_ID(0) |
- PACKET3_QUERY_STATUS_INTERRUPT_SEL(0) |
- PACKET3_QUERY_STATUS_COMMAND(2));
- amdgpu_ring_write(kiq_ring, /* Q_sel: 0, vmid: 0, engine: 0, num_Q: 1 */
- PACKET3_QUERY_STATUS_DOORBELL_OFFSET(ring->doorbell_index) |
- PACKET3_QUERY_STATUS_ENG_SEL(eng_sel));
- amdgpu_ring_write(kiq_ring, lower_32_bits(addr));
- amdgpu_ring_write(kiq_ring, upper_32_bits(addr));
- amdgpu_ring_write(kiq_ring, lower_32_bits(seq));
- amdgpu_ring_write(kiq_ring, upper_32_bits(seq));
-}
-
-static void gfx_v12_1_kiq_invalidate_tlbs(struct amdgpu_ring *kiq_ring,
- uint16_t pasid,
- uint32_t flush_type,
- bool all_hub)
-{
- gfx_v12_1_ring_invalidate_tlbs(kiq_ring, pasid, flush_type, all_hub, 1);
-}
-
-static const struct kiq_pm4_funcs gfx_v12_1_kiq_pm4_funcs = {
- .kiq_set_resources = gfx_v12_1_kiq_set_resources,
- .kiq_map_queues = gfx_v12_1_kiq_map_queues,
- .kiq_unmap_queues = gfx_v12_1_kiq_unmap_queues,
- .kiq_query_status = gfx_v12_1_kiq_query_status,
- .kiq_invalidate_tlbs = gfx_v12_1_kiq_invalidate_tlbs,
- .set_resources_size = 8,
- .map_queues_size = 7,
- .unmap_queues_size = 6,
- .query_status_size = 7,
- .invalidate_tlbs_size = 2,
-};
-
-static void gfx_v12_1_set_kiq_pm4_funcs(struct amdgpu_device *adev)
-{
- int i, num_xcc;
-
- num_xcc = NUM_XCC(adev->gfx.xcc_mask);
- for (i =0; i < num_xcc; i++)
- adev->gfx.kiq[i].pmf = &gfx_v12_1_kiq_pm4_funcs;
-}
-
static void gfx_v12_1_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
int mem_space, int opt, uint32_t addr0,
uint32_t addr1, uint32_t ref,
@@ -403,14 +262,9 @@ static int gfx_v12_1_ring_test_ring(struct amdgpu_ring *ring)
return r;
}
- if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ) {
- gfx_v12_1_ring_emit_wreg(ring, xcc_offset, 0xDEADBEEF);
- } else {
- amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
- amdgpu_ring_write(ring, xcc_offset -
- PACKET3_SET_UCONFIG_REG_START);
- amdgpu_ring_write(ring, 0xDEADBEEF);
- }
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+ amdgpu_ring_write(ring, xcc_offset - PACKET3_SET_UCONFIG_REG_START);
+ amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
for (i = 0; i < adev->usec_timeout; i++) {
@@ -439,11 +293,6 @@ static int gfx_v12_1_ring_test_ib(struct amdgpu_ring *ring, long timeout)
volatile uint32_t *cpu_ptr;
long r;
- /* MES KIQ fw hasn't indirect buffer support for now */
- if (adev->enable_mes_kiq &&
- ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
- return 0;
-
r = amdgpu_wb_get(adev, &index);
if (r)
return r;
@@ -1538,18 +1387,6 @@ static int gfx_v12_1_sw_init(struct amdgpu_ip_block *ip_block)
}
}
- if (!adev->enable_mes_kiq) {
- r = amdgpu_gfx_kiq_init(adev, GFX12_MEC_HPD_SIZE, xcc_id);
- if (r) {
- dev_err(adev->dev, "Failed to init KIQ BOs!\n");
- return r;
- }
-
- r = amdgpu_gfx_kiq_init_ring(adev, xcc_id);
- if (r)
- return r;
- }
-
r = amdgpu_gfx_mqd_sw_init(adev, sizeof(struct v12_1_compute_mqd), xcc_id);
if (r)
return r;
@@ -1600,15 +1437,9 @@ static int gfx_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->gfx.num_compute_rings * num_xcc; i++)
amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
- for (i = 0; i < num_xcc; i++) {
+ for (i = 0; i < num_xcc; i++)
amdgpu_gfx_mqd_sw_fini(adev, i);
- if (!adev->enable_mes_kiq) {
- amdgpu_gfx_kiq_free_ring(&adev->gfx.kiq[i].ring);
- amdgpu_gfx_kiq_fini(adev, i);
- }
- }
-
gfx_v12_1_rlc_fini(adev);
gfx_v12_1_mec_fini(adev);
@@ -2193,8 +2024,6 @@ static void gfx_v12_1_xcc_cp_compute_enable(struct amdgpu_device *adev,
enable ? 0 : 1);
WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MEC_RS64_CNTL, data);
- adev->gfx.kiq[xcc_id].ring.sched.ready = enable;
-
udelay(50);
}
@@ -2357,21 +2186,6 @@ static int gfx_v12_1_xcc_cp_compute_load_microcode_rs64(struct amdgpu_device *ad
return 0;
}
-static void gfx_v12_1_xcc_kiq_setting(struct amdgpu_ring *ring,
- int xcc_id)
-{
- uint32_t tmp;
- struct amdgpu_device *adev = ring->adev;
-
- /* tell RLC which is KIQ queue */
- tmp = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regRLC_CP_SCHEDULERS);
- tmp &= 0xffffff00;
- tmp |= (ring->me << 5) | (ring->pipe << 3) | (ring->queue);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regRLC_CP_SCHEDULERS, tmp);
- tmp |= 0x80;
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regRLC_CP_SCHEDULERS, tmp);
-}
-
static void gfx_v12_1_xcc_cp_set_doorbell_range(struct amdgpu_device *adev,
int xcc_id)
{
@@ -2527,149 +2341,6 @@ static int gfx_v12_1_compute_mqd_init(struct amdgpu_device *adev, void *m,
return 0;
}
-static int gfx_v12_1_xcc_kiq_init_register(struct amdgpu_ring *ring,
- int xcc_id)
-{
- struct amdgpu_device *adev = ring->adev;
- struct v12_1_compute_mqd *mqd = ring->mqd_ptr;
- int j;
-
- /* inactivate the queue */
- if (amdgpu_sriov_vf(adev))
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE, 0);
-
- /* disable wptr polling */
- WREG32_FIELD15_PREREG(GC, GET_INST(GC, xcc_id), CP_PQ_WPTR_POLL_CNTL, EN, 0);
-
- /* write the EOP addr */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_EOP_BASE_ADDR,
- mqd->cp_hqd_eop_base_addr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_EOP_BASE_ADDR_HI,
- mqd->cp_hqd_eop_base_addr_hi);
-
- /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_EOP_CONTROL,
- mqd->cp_hqd_eop_control);
-
- /* enable doorbell? */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_DOORBELL_CONTROL,
- mqd->cp_hqd_pq_doorbell_control);
-
- /* disable the queue if it's active */
- if (RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE) & 1) {
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_DEQUEUE_REQUEST, 1);
- for (j = 0; j < adev->usec_timeout; j++) {
- if (!(RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE) & 1))
- break;
- udelay(1);
- }
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_DEQUEUE_REQUEST,
- mqd->cp_hqd_dequeue_request);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_RPTR,
- mqd->cp_hqd_pq_rptr);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_LO,
- mqd->cp_hqd_pq_wptr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_HI,
- mqd->cp_hqd_pq_wptr_hi);
- }
-
- /* set the pointer to the MQD */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MQD_BASE_ADDR,
- mqd->cp_mqd_base_addr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MQD_BASE_ADDR_HI,
- mqd->cp_mqd_base_addr_hi);
-
- /* set MQD vmid to 0 */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MQD_CONTROL,
- mqd->cp_mqd_control);
-
- /* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_BASE,
- mqd->cp_hqd_pq_base_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_BASE_HI,
- mqd->cp_hqd_pq_base_hi);
-
- /* set up the HQD, this is similar to CP_RB0_CNTL */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_CONTROL,
- mqd->cp_hqd_pq_control);
-
- /* set the wb address whether it's enabled or not */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_RPTR_REPORT_ADDR,
- mqd->cp_hqd_pq_rptr_report_addr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_RPTR_REPORT_ADDR_HI,
- mqd->cp_hqd_pq_rptr_report_addr_hi);
-
- /* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_POLL_ADDR,
- mqd->cp_hqd_pq_wptr_poll_addr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_POLL_ADDR_HI,
- mqd->cp_hqd_pq_wptr_poll_addr_hi);
-
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_DOORBELL_CONTROL,
- mqd->cp_hqd_pq_doorbell_control);
-
- /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_LO,
- mqd->cp_hqd_pq_wptr_lo);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_HI,
- mqd->cp_hqd_pq_wptr_hi);
-
- /* set the vmid for the queue */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_VMID, mqd->cp_hqd_vmid);
-
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PERSISTENT_STATE,
- mqd->cp_hqd_persistent_state);
-
- /* activate the queue */
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE,
- mqd->cp_hqd_active);
-
- if (ring->use_doorbell)
- WREG32_FIELD15_PREREG(GC, GET_INST(GC, xcc_id), CP_PQ_STATUS, DOORBELL_ENABLE, 1);
-
- return 0;
-}
-
-static int gfx_v12_1_xcc_kiq_init_queue(struct amdgpu_ring *ring,
- int xcc_id)
-{
- struct amdgpu_device *adev = ring->adev;
- struct v12_1_compute_mqd *mqd = ring->mqd_ptr;
-
- gfx_v12_1_xcc_kiq_setting(ring, xcc_id);
-
- if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */
- /* reset MQD to a clean status */
- if (adev->gfx.kiq[xcc_id].mqd_backup)
- memcpy(mqd, adev->gfx.kiq[xcc_id].mqd_backup, sizeof(*mqd));
-
- /* reset ring buffer */
- ring->wptr = 0;
- amdgpu_ring_clear_ring(ring);
-
- mutex_lock(&adev->srbm_mutex);
- soc_v1_0_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0, GET_INST(GC, xcc_id));
- gfx_v12_1_xcc_kiq_init_register(ring, xcc_id);
- soc_v1_0_grbm_select(adev, 0, 0, 0, 0, GET_INST(GC, xcc_id));
- mutex_unlock(&adev->srbm_mutex);
- } else {
- memset((void *)mqd, 0, sizeof(*mqd));
- if (amdgpu_sriov_vf(adev) && adev->in_suspend)
- amdgpu_ring_clear_ring(ring);
- mutex_lock(&adev->srbm_mutex);
- soc_v1_0_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0, GET_INST(GC, xcc_id));
- amdgpu_ring_init_mqd(ring);
- gfx_v12_1_xcc_kiq_init_register(ring, xcc_id);
- soc_v1_0_grbm_select(adev, 0, 0, 0, 0, GET_INST(GC, xcc_id));
- mutex_unlock(&adev->srbm_mutex);
-
- if (adev->gfx.kiq[xcc_id].mqd_backup)
- memcpy(adev->gfx.kiq[xcc_id].mqd_backup, mqd, sizeof(*mqd));
- }
-
- return 0;
-}
-
static int gfx_v12_1_xcc_kcq_init_queue(struct amdgpu_ring *ring,
int xcc_id)
{
@@ -2700,32 +2371,6 @@ static int gfx_v12_1_xcc_kcq_init_queue(struct amdgpu_ring *ring,
return 0;
}
-static int gfx_v12_1_xcc_kiq_resume(struct amdgpu_device *adev,
- int xcc_id)
-{
- struct amdgpu_ring *ring;
- int r;
-
- ring = &adev->gfx.kiq[xcc_id].ring;
-
- r = amdgpu_bo_reserve(ring->mqd_obj, false);
- if (unlikely(r != 0))
- return r;
-
- r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
- if (unlikely(r != 0)) {
- amdgpu_bo_unreserve(ring->mqd_obj);
- return r;
- }
-
- gfx_v12_1_xcc_kiq_init_queue(ring, xcc_id);
- amdgpu_bo_kunmap(ring->mqd_obj);
- ring->mqd_ptr = NULL;
- amdgpu_bo_unreserve(ring->mqd_obj);
- ring->sched.ready = true;
- return 0;
-}
-
static int gfx_v12_1_xcc_kcq_resume(struct amdgpu_device *adev,
int xcc_id)
{
@@ -2762,6 +2407,9 @@ static int gfx_v12_1_xcc_cp_resume(struct amdgpu_device *adev, uint16_t xcc_mask
int r, i, xcc_id;
struct amdgpu_ring *ring;
+ if (!adev->mes.kiq_hw_init)
+ return -EINVAL;
+
for_each_inst(xcc_id, xcc_mask) {
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
/* legacy firmware loading */
@@ -2779,19 +2427,7 @@ static int gfx_v12_1_xcc_cp_resume(struct amdgpu_device *adev, uint16_t xcc_mask
gfx_v12_1_xcc_cp_compute_enable(adev, true, xcc_id);
- if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) {
- r = amdgpu_mes_kiq_hw_init(adev, xcc_id);
- /*
- * With MES, GFX KIQ ring is owned by the MES and is never
- * initialized/used directly by the driver, so it must
- * not be left flagged as ready. mes_v12_0_hw_init() clears
- * but clear here if MES init fails
- */
- if (r)
- adev->gfx.kiq[xcc_id].ring.sched.ready = false;
- } else {
- r = gfx_v12_1_xcc_kiq_resume(adev, xcc_id);
- }
+ r = amdgpu_mes_kiq_hw_init(adev, xcc_id);
if (r)
return r;
@@ -3184,7 +2820,6 @@ static int gfx_v12_1_early_init(struct amdgpu_ip_block *ip_block)
adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
AMDGPU_MAX_COMPUTE_RINGS);
- gfx_v12_1_set_kiq_pm4_funcs(adev);
gfx_v12_1_set_ring_funcs(adev);
gfx_v12_1_set_irq_funcs(adev);
gfx_v12_1_set_rlc_funcs(adev);
@@ -3685,18 +3320,6 @@ static void gfx_v12_1_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
upper_32_bits(addr), seq, 0xffffffff, 4);
}
-static void gfx_v12_1_ring_invalidate_tlbs(struct amdgpu_ring *ring,
- uint16_t pasid, uint32_t flush_type,
- bool all_hub, uint8_t dst_sel)
-{
- amdgpu_ring_write(ring, PACKET3(PACKET3_INVALIDATE_TLBS, 0));
- amdgpu_ring_write(ring,
- PACKET3_INVALIDATE_TLBS_DST_SEL(dst_sel) |
- PACKET3_INVALIDATE_TLBS_ALL_HUB(all_hub) |
- PACKET3_INVALIDATE_TLBS_PASID(pasid) |
- PACKET3_INVALIDATE_TLBS_FLUSH_TYPE(flush_type));
-}
-
static void gfx_v12_1_ring_emit_vm_flush(struct amdgpu_ring *ring,
unsigned vmid, uint64_t pd_addr)
{
@@ -3705,65 +3328,14 @@ static void gfx_v12_1_ring_emit_vm_flush(struct amdgpu_ring *ring,
/* compute doesn't have PFP */
}
-static void gfx_v12_1_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
- u64 seq, unsigned int flags)
-{
- struct amdgpu_device *adev = ring->adev;
-
- /* write fence seq to the "addr" */
- amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
- amdgpu_ring_write(ring, (PACKET3_WRITE_DATA__DST_SEL(5) | PACKET3_WRITE_DATA__WR_CONFIRM(1)));
- amdgpu_ring_write(ring, lower_32_bits(addr));
- amdgpu_ring_write(ring, upper_32_bits(addr));
- amdgpu_ring_write(ring, lower_32_bits(seq));
-
- if (flags & AMDGPU_FENCE_FLAG_INT) {
- /* set register to trigger INT */
- amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
- amdgpu_ring_write(ring, (PACKET3_WRITE_DATA__DST_SEL(0) | PACKET3_WRITE_DATA__WR_CONFIRM(1)));
- amdgpu_ring_write(ring, SOC15_REG_OFFSET(GC, GET_INST(GC, 0), regCPC_INT_STATUS));
- amdgpu_ring_write(ring, 0);
- amdgpu_ring_write(ring, 0x20000000); /* src_id is 178 */
- }
-}
-
-static void gfx_v12_1_ring_emit_rreg(struct amdgpu_ring *ring, uint32_t reg,
- uint32_t reg_val_offs)
-{
- struct amdgpu_device *adev = ring->adev;
-
- reg = soc_v1_0_normalize_xcc_reg_offset(reg);
-
- amdgpu_ring_write(ring, PACKET3(PACKET3_COPY_DATA, 4));
- amdgpu_ring_write(ring, 0 | /* src: register*/
- (5 << 8) | /* dst: memory */
- (1 << 20)); /* write confirm */
- amdgpu_ring_write(ring, reg);
- amdgpu_ring_write(ring, 0);
- amdgpu_ring_write(ring, lower_32_bits(adev->wb.gpu_addr +
- reg_val_offs * 4));
- amdgpu_ring_write(ring, upper_32_bits(adev->wb.gpu_addr +
- reg_val_offs * 4));
-}
-
static void gfx_v12_1_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg,
uint32_t val)
{
- uint32_t cmd = 0;
-
reg = soc_v1_0_normalize_xcc_reg_offset(reg);
- switch (ring->funcs->type) {
- case AMDGPU_RING_TYPE_KIQ:
- cmd = (1 << 16); /* no inc addr */
- break;
- default:
- cmd = PACKET3_WRITE_DATA__WR_CONFIRM(1);
- break;
- }
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
- amdgpu_ring_write(ring, cmd);
+ amdgpu_ring_write(ring, PACKET3_WRITE_DATA__WR_CONFIRM(1));
amdgpu_ring_write(ring, reg);
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring, val);
@@ -4157,41 +3729,12 @@ static const struct amdgpu_ring_funcs gfx_v12_1_ring_funcs_compute = {
.emit_mem_sync = gfx_v12_1_emit_mem_sync,
};
-static const struct amdgpu_ring_funcs gfx_v12_1_ring_funcs_kiq = {
- .type = AMDGPU_RING_TYPE_KIQ,
- .align_mask = 0xff,
- .nop = PACKET3(PACKET3_NOP, 0x3FFF),
- .support_64bit_ptrs = true,
- .get_rptr = gfx_v12_1_ring_get_rptr_compute,
- .get_wptr = gfx_v12_1_ring_get_wptr_compute,
- .set_wptr = gfx_v12_1_ring_set_wptr_compute,
- .emit_frame_size =
- 7 + /* gfx_v12_1_ring_emit_pipeline_sync */
- SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 +
- SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 +
- 2 + /* gfx_v12_1_ring_emit_vm_flush */
- 8 + 8 + 8, /* gfx_v12_1_ring_emit_fence_kiq x3 for user fence, vm fence */
- .emit_ib_size = 7, /* gfx_v12_1_ring_emit_ib_compute */
- .emit_ib = gfx_v12_1_ring_emit_ib_compute,
- .emit_fence = gfx_v12_1_ring_emit_fence_kiq,
- .test_ring = gfx_v12_1_ring_test_ring,
- .test_ib = gfx_v12_1_ring_test_ib,
- .insert_nop = amdgpu_ring_insert_nop,
- .pad_ib = amdgpu_ring_generic_pad_ib,
- .emit_rreg = gfx_v12_1_ring_emit_rreg,
- .emit_wreg = gfx_v12_1_ring_emit_wreg,
- .emit_reg_wait = gfx_v12_1_ring_emit_reg_wait,
- .emit_reg_write_reg_wait = gfx_v12_1_ring_emit_reg_write_reg_wait,
-};
-
static void gfx_v12_1_set_ring_funcs(struct amdgpu_device *adev)
{
int i, j, num_xcc;
num_xcc = NUM_XCC(adev->gfx.xcc_mask);
for (i = 0; i < num_xcc; i++) {
- adev->gfx.kiq[i].ring.funcs = &gfx_v12_1_ring_funcs_kiq;
-
for (j = 0; j < adev->gfx.num_compute_rings; j++)
adev->gfx.compute_ring[j + i * adev->gfx.num_compute_rings].funcs =
&gfx_v12_1_ring_funcs_compute;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c
index 8b84bba58752..344156bf20ca 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c
@@ -343,6 +343,28 @@ const struct soc15_reg_entry sgpr64_init_regs_aldebaran[] = {
{ SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE7), 0xffffffff },
};
+static const u32 fault_cleaner_compute_shader_aldebaran[] = {
+ 0xbe8000ff, 0x00001000, 0x80808100, 0x86000000, 0xbf85fffd, 0xbf810000
+};
+
+const struct soc15_reg_entry fault_cleaner_init_regs_aldebaran[] = {
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_RESOURCE_LIMITS), 0x0000000 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_NUM_THREAD_X), 0x40 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_NUM_THREAD_Y), 1 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_NUM_THREAD_Z), 1 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_PGM_RSRC1), 0xaf0000 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_PGM_RSRC2), 0xc8 },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_PGM_RSRC3), 0xea4fac },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE0), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE1), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE2), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE3), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE4), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE5), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE6), 0xffffffff },
+ { SOC15_REG_ENTRY(GC, 0, regCOMPUTE_STATIC_THREAD_MGMT_SE7), 0xffffffff },
+};
+
static int gfx_v9_4_2_run_shader(struct amdgpu_device *adev,
struct amdgpu_ring *ring,
const u32 *shader_ptr, u32 shader_size,
@@ -692,6 +714,67 @@ pro_end:
return r;
}
+static int gfx_v9_4_2_clean_shaders(struct amdgpu_device *adev)
+{
+ int r;
+ /* CU_ID: 0~15, SIMD_ID: 0~3, WAVE_ID: 0 ~ 9 */
+ int wb_size = adev->gfx.config.max_shader_engines *
+ CU_ID_MAX * SIMD_ID_MAX * WAVE_ID_MAX;
+ struct amdgpu_ib wb_ib;
+ struct dma_fence *fence = NULL;
+ u32 pattern = 0xa;
+
+ /* bail if the compute ring is not ready */
+ if (!adev->gfx.compute_ring[0].sched.ready)
+ return 0;
+
+ /* allocate the write-back buffer from IB */
+ memset(&wb_ib, 0, sizeof(wb_ib));
+ r = amdgpu_ib_get(adev, NULL, (1 + wb_size) * sizeof(uint32_t),
+ AMDGPU_IB_POOL_DIRECT, &wb_ib);
+ if (r) {
+ dev_err(adev->dev, "failed to get ib (%d) for wb.\n", r);
+ return r;
+ }
+ memset(wb_ib.ptr, 0, (1 + wb_size) * sizeof(uint32_t));
+
+ r = gfx_v9_4_2_run_shader(adev,
+ &adev->gfx.compute_ring[0],
+ fault_cleaner_compute_shader_aldebaran,
+ sizeof(fault_cleaner_compute_shader_aldebaran),
+ fault_cleaner_init_regs_aldebaran,
+ ARRAY_SIZE(fault_cleaner_init_regs_aldebaran),
+ adev->gfx.cu_info.number * 32,
+ wb_ib.gpu_addr, pattern, &fence);
+
+ if (r) {
+ dev_err(adev->dev, "failed to clear MI200\n");
+ goto pro_end;
+ }
+
+ /* wait for the GPU to finish processing the IB */
+ r = dma_fence_wait(fence, false);
+ if (r)
+ dev_err(adev->dev, "timeout to clear MI200\n");
+
+pro_end:
+ if (fence)
+ dma_fence_put(fence);
+ amdgpu_ib_free(&wb_ib, NULL);
+
+ if (r)
+ dev_dbg(adev->dev, "Clean MI200 Failed\n");
+ else
+ dev_dbg(adev->dev, "Clean MI200 Successfully\n");
+
+ return r;
+}
+
+void gfx_v9_4_2_clean_fault(struct amdgpu_device *adev)
+{
+ gfx_v9_4_2_clean_shaders(adev);
+}
+
int gfx_v9_4_2_do_edc_gpr_workarounds(struct amdgpu_device *adev)
{
/* only support when RAS is enabled */
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.h b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.h
index a603724c1dfc..1cbade5ed657 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.h
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.h
@@ -30,6 +30,7 @@ void gfx_v9_4_2_init_golden_registers(struct amdgpu_device *adev,
uint32_t die_id);
void gfx_v9_4_2_init_sq(struct amdgpu_device *adev);
void gfx_v9_4_2_set_power_brake_sequence(struct amdgpu_device *adev);
+void gfx_v9_4_2_clean_fault(struct amdgpu_device *adev);
int gfx_v9_4_2_do_edc_gpr_workarounds(struct amdgpu_device *adev);
extern struct amdgpu_gfx_ras gfx_v9_4_2_ras;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
index ce48da12edb2..484ecde55ac9 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_gfx.h"
#include "soc15.h"
#include "soc15d.h"
@@ -1646,10 +1647,9 @@ static bool gfx_v9_4_3_check_rlcg_range(struct amdgpu_device *adev,
const struct soc15_reg_rlcg *entry;
entry = &entries[i];
- inst = adev->ip_map.logical_to_dev_inst ?
- adev->ip_map.logical_to_dev_inst(
- adev, entry->hwip, entry->instance) :
- entry->instance;
+ inst = amdgpu_ip_map_logical_to_dev_inst(&adev->ip_map,
+ entry->hwip,
+ entry->instance);
reg = adev->reg_offset[entry->hwip][inst][entry->segment] +
entry->reg;
if (offset == reg)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
index 8397d3d38287..e89813590539 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
@@ -21,6 +21,7 @@
*
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_xcp.h"
#include "gfxhub_v1_2.h"
#include "gfxhub_v1_1.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index 9a8a7921ce98..490b4c4eb662 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -26,6 +26,7 @@
#include <drm/drm_cache.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_atomfirmware.h"
#include "gmc_v10_0.h"
#include "umc_v8_7.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index bee269a8877a..3cdc7893587a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -26,6 +26,7 @@
#include <drm/drm_cache.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_atomfirmware.h"
#include "gmc_v11_0.h"
#include "umc_v8_10.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index b6cd6babb035..d7f56bbcfd44 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -27,6 +27,7 @@
#include "amdgpu.h"
#include "amdgpu_atomfirmware.h"
+#include "amdgpu_ip.h"
#include "gmc_v12_0.h"
#include "gmc_v12_1.h"
#include "athub/athub_4_1_0_sh_mask.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c
index 565ee7fba3cd..3349e8bc1c20 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c
@@ -407,9 +407,8 @@ static void gmc_v12_1_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
/* This is necessary for SRIOV as well as for GFXOFF to function
* properly under bare metal
*/
- if (((adev->gfx.kiq[inst].ring.sched.ready ||
- adev->mes.ring[MES_PIPE_INST(inst, 0)].sched.ready) &&
- (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)))) {
+ if (adev->mes.ring[MES_PIPE_INST(inst, 0)].sched.ready &&
+ (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) {
struct amdgpu_vmhub *hub = &adev->vmhub[vmhub];
const unsigned eng = 17;
u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type);
@@ -432,7 +431,7 @@ static void gmc_v12_1_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
* @pasid: pasid to be flush
* @flush_type: the flush type
* @all_hub: flush all hubs
- * @inst: is used to select which instance of KIQ to use for the invalidation
+ * @inst: XCC instance to use for the invalidation
*
* Flush the TLB for the requested pasid.
*/
@@ -443,7 +442,7 @@ static void gmc_v12_1_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
uint16_t queried;
int vmid, i;
- if (adev->enable_uni_mes && adev->mes.ring[0].sched.ready &&
+ if (adev->mes.ring[0].sched.ready &&
(adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x6f) {
struct mes_inv_tlbs_pasid_input input = {0};
input.xcc_id = inst;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 633772fa71fd..5245d8850a42 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -63,6 +63,7 @@
#include "ivsrcid/vmc/irqsrcs_vmc_1_0.h"
+#include "amdgpu_ip.h"
#include "amdgpu_ras.h"
#include "amdgpu_xgmi.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index 49f84e6647a5..0343a64595f2 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -22,6 +22,7 @@
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_jpeg.h"
#include "soc15.h"
#include "soc15d.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index 197d1af18a3a..4da3f9c995c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -22,6 +22,7 @@
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_jpeg.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 9b57fdc1e69a..dcdb089b4308 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -22,6 +22,7 @@
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_jpeg.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
index f67868132bed..f2debf6b6bd0 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
@@ -22,6 +22,7 @@
*/
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_jpeg.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 68beccee9fc0..fe49aa4dc5ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -60,7 +60,8 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
}
obj = wptr_mapping->bo_va->base.bo;
- ret = drm_exec_lock_obj(&exec, &obj->tbo.base);
+ ret = drm_exec_prepare_obj(&exec, &obj->tbo.base,
+ TTM_NUM_MOVE_FENCES + 1);
drm_exec_retry_on_contention(&exec);
if (unlikely(ret))
goto fail_lock;
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
index c827eb46058a..7459547b7a69 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
@@ -34,8 +34,6 @@
#include "gfx_v12_1_pkt.h"
#include "sdma_v7_1_0_pkt_open.h"
-MODULE_FIRMWARE("amdgpu/gc_12_1_0_mes.bin");
-MODULE_FIRMWARE("amdgpu/gc_12_1_0_mes1.bin");
MODULE_FIRMWARE("amdgpu/gc_12_1_0_uni_mes.bin");
static int mes_v12_1_hw_init(struct amdgpu_ip_block *ip_block);
@@ -414,15 +412,11 @@ static int mes_v12_1_map_legacy_queue(struct amdgpu_mes *mes,
convert_to_mes_queue_type(input->queue_type);
mes_add_queue_pkt.map_legacy_kq = 1;
- if (mes->adev->enable_uni_mes) {
- /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
- if (input->queue_type == AMDGPU_RING_TYPE_MES)
- pipe = AMDGPU_MES_KIQ_PIPE;
- else
- pipe = AMDGPU_MES_SCHED_PIPE;
- } else {
+ /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
+ if (input->queue_type == AMDGPU_RING_TYPE_MES)
+ pipe = AMDGPU_MES_KIQ_PIPE;
+ else
pipe = AMDGPU_MES_SCHED_PIPE;
- }
return mes_v12_1_submit_pkt_and_poll_completion(mes,
input->xcc_id, pipe,
@@ -459,15 +453,11 @@ static int mes_v12_1_unmap_legacy_queue(struct amdgpu_mes *mes,
convert_to_mes_queue_type(input->queue_type);
}
- if (mes->adev->enable_uni_mes) {
- /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
- if (input->queue_type == AMDGPU_RING_TYPE_MES)
- pipe = AMDGPU_MES_KIQ_PIPE;
- else
- pipe = AMDGPU_MES_SCHED_PIPE;
- } else {
+ /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
+ if (input->queue_type == AMDGPU_RING_TYPE_MES)
+ pipe = AMDGPU_MES_KIQ_PIPE;
+ else
pipe = AMDGPU_MES_SCHED_PIPE;
- }
return mes_v12_1_submit_pkt_and_poll_completion(mes,
input->xcc_id, pipe,
@@ -567,7 +557,7 @@ static int mes_v12_1_misc_op(struct amdgpu_mes *mes,
int pipe;
/*OP_WRM_REG_WR_WAIT is used to do tlb invalidation which need to be handled in sched pipe for gfx_12_1.*/
- if (mes->adev->enable_uni_mes && input->op != MES_MISC_OP_WRM_REG_WR_WAIT)
+ if (input->op != MES_MISC_OP_WRM_REG_WR_WAIT)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
@@ -766,7 +756,7 @@ static int mes_v12_1_set_hw_resources(struct amdgpu_mes *mes,
if (pipe == AMDGPU_MES_SCHED_PIPE)
adev->mes.sched_version = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MES_GP3_LO);
- else if (pipe == AMDGPU_MES_KIQ_PIPE && adev->enable_mes_kiq)
+ else if (pipe == AMDGPU_MES_KIQ_PIPE)
adev->mes.kiq_version = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MES_GP3_LO);
soc_v1_0_grbm_select(adev, 0, 0, 0, 0, GET_INST(GC, xcc_id));
@@ -880,10 +870,7 @@ static int mes_v12_1_reset_legacy_queue(struct amdgpu_mes *mes,
mes_reset_queue_pkt.doorbell_offset = input->doorbell_offset;
}
- if (mes->adev->enable_uni_mes)
- pipe = AMDGPU_MES_KIQ_PIPE;
- else
- pipe = AMDGPU_MES_SCHED_PIPE;
+ pipe = AMDGPU_MES_KIQ_PIPE;
return mes_v12_1_submit_pkt_and_poll_completion(mes,
input->xcc_id, pipe,
@@ -1100,10 +1087,8 @@ static void mes_v12_1_enable(struct amdgpu_device *adev,
if (amdgpu_emu_mode)
msleep(500);
- else if (adev->enable_uni_mes)
- udelay(500);
else
- udelay(50);
+ udelay(500);
} else {
data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_MES_CNTL);
data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_ACTIVE, 0);
@@ -1317,6 +1302,7 @@ static int mes_v12_1_mqd_init(struct amdgpu_ring *ring)
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
((order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1) << 8));
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, SCOPE, 3);
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0);
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1);
@@ -1426,31 +1412,6 @@ static void mes_v12_1_queue_init_register(struct amdgpu_ring *ring,
mutex_unlock(&adev->srbm_mutex);
}
-static int mes_v12_1_kiq_enable_queue(struct amdgpu_device *adev, int xcc_id)
-{
- struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_id];
- struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[xcc_id].ring;
- int r, inst = MES_PIPE_INST(xcc_id, AMDGPU_MES_SCHED_PIPE);
-
- if (!kiq->pmf || !kiq->pmf->kiq_map_queues)
- return -EINVAL;
-
- r = amdgpu_ring_alloc(kiq_ring, kiq->pmf->map_queues_size);
- if (r) {
- DRM_ERROR("Failed to lock KIQ (%d).\n", r);
- return r;
- }
-
- kiq->pmf->kiq_map_queues(kiq_ring, &adev->mes.ring[inst]);
-
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r) {
- DRM_ERROR("kfq enable failed\n");
- kiq_ring->sched.ready = false;
- }
- return r;
-}
-
static int mes_v12_1_queue_init(struct amdgpu_device *adev,
enum amdgpu_mes_pipe pipe,
int xcc_id)
@@ -1458,13 +1419,9 @@ static int mes_v12_1_queue_init(struct amdgpu_device *adev,
struct amdgpu_ring *ring;
int r;
- if (!adev->enable_uni_mes && pipe == AMDGPU_MES_KIQ_PIPE)
- ring = &adev->gfx.kiq[xcc_id].ring;
- else
- ring = &adev->mes.ring[MES_PIPE_INST(xcc_id, pipe)];
+ ring = &adev->mes.ring[MES_PIPE_INST(xcc_id, pipe)];
- if ((adev->enable_uni_mes || pipe == AMDGPU_MES_SCHED_PIPE) &&
- (amdgpu_in_reset(adev) || adev->in_suspend)) {
+ if (amdgpu_in_reset(adev) || adev->in_suspend) {
*(ring->wptr_cpu_addr) = 0;
*(ring->rptr_cpu_addr) = 0;
amdgpu_ring_clear_ring(ring);
@@ -1475,10 +1432,7 @@ static int mes_v12_1_queue_init(struct amdgpu_device *adev,
return r;
if (pipe == AMDGPU_MES_SCHED_PIPE) {
- if (adev->enable_uni_mes)
- r = amdgpu_mes_map_legacy_queue(adev, ring, xcc_id);
- else
- r = mes_v12_1_kiq_enable_queue(adev, xcc_id);
+ r = amdgpu_mes_map_legacy_queue(adev, ring, xcc_id);
if (r)
return r;
} else {
@@ -1527,39 +1481,6 @@ static int mes_v12_1_ring_init(struct amdgpu_device *adev,
AMDGPU_RING_PRIO_DEFAULT, NULL);
}
-static int mes_v12_1_kiq_ring_init(struct amdgpu_device *adev, int xcc_id)
-{
- struct amdgpu_ring *ring;
- int inst = MES_PIPE_INST(xcc_id, AMDGPU_MES_KIQ_PIPE);
-
- spin_lock_init(&adev->gfx.kiq[xcc_id].ring_lock);
-
- ring = &adev->gfx.kiq[xcc_id].ring;
-
- ring->me = 3;
- ring->pipe = 1;
- ring->queue = 0;
- ring->xcc_id = xcc_id;
- ring->vm_hub = AMDGPU_GFXHUB(xcc_id);
-
- ring->adev = NULL;
- ring->ring_obj = NULL;
- ring->use_doorbell = true;
- ring->eop_gpu_addr = adev->mes.eop_gpu_addr[inst];
- ring->no_scheduler = true;
- ring->doorbell_index =
- (adev->doorbell_index.mes_ring1 +
- xcc_id * adev->doorbell_index.xcc_doorbell_range)
- << 1;
-
- snprintf(ring->name, sizeof(ring->name), "mes_kiq_%hhu.%hhu.%hhu.%hhu",
- (unsigned char)xcc_id, (unsigned char)ring->me,
- (unsigned char)ring->pipe, (unsigned char)ring->queue);
-
- return amdgpu_ring_init(adev, ring, 1024, NULL, 0,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
-}
-
static int mes_v12_1_mqd_sw_init(struct amdgpu_device *adev,
enum amdgpu_mes_pipe pipe,
int xcc_id)
@@ -1568,10 +1489,7 @@ static int mes_v12_1_mqd_sw_init(struct amdgpu_device *adev,
struct amdgpu_ring *ring;
int inst = MES_PIPE_INST(xcc_id, pipe);
- if (!adev->enable_uni_mes && pipe == AMDGPU_MES_KIQ_PIPE)
- ring = &adev->gfx.kiq[xcc_id].ring;
- else
- ring = &adev->mes.ring[inst];
+ ring = &adev->mes.ring[inst];
if (ring->mqd_obj)
return 0;
@@ -1606,8 +1524,8 @@ static int mes_v12_1_sw_init(struct amdgpu_ip_block *ip_block)
adev->mes.kiq_hw_fini = &mes_v12_1_kiq_hw_fini;
adev->mes.enable_legacy_queue_map = true;
- adev->mes.event_log_size =
- adev->enable_uni_mes ? (AMDGPU_MAX_MES_PIPES * AMDGPU_MES_LOG_BUFFER_SIZE * num_xcc) : AMDGPU_MES_LOG_BUFFER_SIZE;
+ adev->mes.event_log_size = AMDGPU_MAX_MES_PIPES *
+ AMDGPU_MES_LOG_BUFFER_SIZE * num_xcc;
r = amdgpu_mes_init(adev);
if (r)
@@ -1623,15 +1541,11 @@ static int mes_v12_1_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
- if (!adev->enable_uni_mes && pipe ==
- AMDGPU_MES_KIQ_PIPE)
- r = mes_v12_1_kiq_ring_init(adev, xcc_id);
- else
- r = mes_v12_1_ring_init(adev, xcc_id, pipe);
+ r = mes_v12_1_ring_init(adev, xcc_id, pipe);
if (r)
return r;
- if (adev->enable_uni_mes && num_xcc > 1) {
+ if (num_xcc > 1) {
r = mes_v12_1_allocate_shared_cmd_buf(adev,
pipe, xcc_id);
if (r)
@@ -1662,12 +1576,10 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
&adev->mes.eop_gpu_addr[inst],
NULL);
- if (adev->enable_uni_mes || pipe == AMDGPU_MES_SCHED_PIPE) {
- amdgpu_bo_free_kernel(&adev->mes.ring[inst].mqd_obj,
- &adev->mes.ring[inst].mqd_gpu_addr,
- &adev->mes.ring[inst].mqd_ptr);
- amdgpu_ring_fini(&adev->mes.ring[inst]);
- }
+ amdgpu_bo_free_kernel(&adev->mes.ring[inst].mqd_obj,
+ &adev->mes.ring[inst].mqd_gpu_addr,
+ &adev->mes.ring[inst].mqd_ptr);
+ amdgpu_ring_fini(&adev->mes.ring[inst]);
}
}
@@ -1675,13 +1587,6 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
amdgpu_ucode_release(&adev->mes.fw[pipe]);
for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) {
- if (!adev->enable_uni_mes) {
- amdgpu_bo_free_kernel(&adev->gfx.kiq[xcc_id].ring.mqd_obj,
- &adev->gfx.kiq[xcc_id].ring.mqd_gpu_addr,
- &adev->gfx.kiq[xcc_id].ring.mqd_ptr);
- amdgpu_ring_fini(&adev->gfx.kiq[xcc_id].ring);
- }
-
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
mes_v12_1_free_ucode_buffers(adev,
AMDGPU_MES_KIQ_PIPE, xcc_id);
@@ -1694,44 +1599,6 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
return 0;
}
-static void mes_v12_1_kiq_dequeue_sched(struct amdgpu_device *adev,
- int xcc_id)
-{
- uint32_t data;
- int i;
-
- mutex_lock(&adev->srbm_mutex);
- soc_v1_0_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0,
- GET_INST(GC, xcc_id));
-
- /* disable the queue if it's active */
- if (RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE) & 1) {
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_DEQUEUE_REQUEST, 1);
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!(RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_ACTIVE) & 1))
- break;
- udelay(1);
- }
- }
- data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_DOORBELL_CONTROL);
- data = REG_SET_FIELD(data, CP_HQD_PQ_DOORBELL_CONTROL,
- DOORBELL_EN, 0);
- data = REG_SET_FIELD(data, CP_HQD_PQ_DOORBELL_CONTROL,
- DOORBELL_HIT, 1);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_DOORBELL_CONTROL, data);
-
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_DOORBELL_CONTROL, 0);
-
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_LO, 0);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_WPTR_HI, 0);
- WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_HQD_PQ_RPTR, 0);
-
- soc_v1_0_grbm_select(adev, 0, 0, 0, 0, GET_INST(GC, xcc_id));
- mutex_unlock(&adev->srbm_mutex);
-
- adev->mes.ring[MES_PIPE_INST(xcc_id, 0)].sched.ready = false;
-}
-
static void mes_v12_1_kiq_dequeue(struct amdgpu_device *adev, int xcc_id)
{
int i;
@@ -1780,10 +1647,7 @@ static int mes_v12_1_kiq_hw_init(struct amdgpu_device *adev, uint32_t xcc_id)
int r = 0;
struct amdgpu_ip_block *ip_block;
- if (adev->enable_uni_mes)
- mes_v12_1_kiq_setting(&adev->mes.ring[inst], xcc_id);
- else
- mes_v12_1_kiq_setting(&adev->gfx.kiq[xcc_id].ring, xcc_id);
+ mes_v12_1_kiq_setting(&adev->mes.ring[inst], xcc_id);
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
@@ -1818,19 +1682,17 @@ static int mes_v12_1_kiq_hw_init(struct amdgpu_device *adev, uint32_t xcc_id)
if (r)
goto failure;
- if (adev->enable_uni_mes) {
- r = mes_v12_1_setup_coop_mode(adev, xcc_id);
- if (r)
- goto failure;
+ r = mes_v12_1_setup_coop_mode(adev, xcc_id);
+ if (r)
+ goto failure;
- r = mes_v12_1_set_hw_resources(&adev->mes,
- AMDGPU_MES_KIQ_PIPE, xcc_id);
- if (r)
- goto failure;
+ r = mes_v12_1_set_hw_resources(&adev->mes,
+ AMDGPU_MES_KIQ_PIPE, xcc_id);
+ if (r)
+ goto failure;
- mes_v12_1_set_hw_resources_1(&adev->mes,
- AMDGPU_MES_KIQ_PIPE, xcc_id);
- }
+ mes_v12_1_set_hw_resources_1(&adev->mes,
+ AMDGPU_MES_KIQ_PIPE, xcc_id);
if (adev->mes.enable_legacy_queue_map) {
r = mes_v12_1_xcc_hw_init(ip_block, xcc_id);
@@ -1850,12 +1712,8 @@ static int mes_v12_1_kiq_hw_fini(struct amdgpu_device *adev, uint32_t xcc_id)
int inst = MES_PIPE_INST(xcc_id, AMDGPU_MES_SCHED_PIPE);
if (adev->mes.ring[inst].sched.ready) {
- if (adev->enable_uni_mes)
- amdgpu_mes_unmap_legacy_queue(adev,
- &adev->mes.ring[inst],
- RESET_QUEUES, 0, 0, xcc_id);
- else
- mes_v12_1_kiq_dequeue_sched(adev, xcc_id);
+ amdgpu_mes_unmap_legacy_queue(adev, &adev->mes.ring[inst],
+ RESET_QUEUES, 0, 0, xcc_id);
adev->mes.ring[inst].sched.ready = false;
}
@@ -1916,26 +1774,6 @@ static int mes_v12_1_xcc_hw_init(struct amdgpu_ip_block *ip_block, int xcc_id)
if (adev->mes.ring[MES_PIPE_INST(xcc_id, 0)].sched.ready)
goto out;
- if (!adev->enable_mes_kiq) {
- if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
- r = mes_v12_1_load_microcode(adev,
- AMDGPU_MES_SCHED_PIPE, true, xcc_id);
- if (r) {
- DRM_ERROR("failed to MES fw, r=%d\n", r);
- return r;
- }
-
- mes_v12_1_set_ucode_start_addr(adev, xcc_id);
-
- } else if (adev->firmware.load_type ==
- AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) {
-
- mes_v12_1_set_ucode_start_addr(adev, xcc_id);
- }
-
- mes_v12_1_enable(adev, true, xcc_id);
- }
-
/* Enable the MES to handle doorbell ring on unmapped queue */
mes_v12_1_enable_unmapped_doorbell_handling(&adev->mes, true, xcc_id);
@@ -1948,10 +1786,7 @@ static int mes_v12_1_xcc_hw_init(struct amdgpu_ip_block *ip_block, int xcc_id)
if (r)
goto failure;
- if (adev->enable_uni_mes) {
- mes_v12_1_set_hw_resources_1(&adev->mes,
- AMDGPU_MES_SCHED_PIPE, xcc_id);
- }
+ mes_v12_1_set_hw_resources_1(&adev->mes, AMDGPU_MES_SCHED_PIPE, xcc_id);
mes_v12_1_init_aggregated_doorbell(&adev->mes, xcc_id);
r = mes_v12_1_query_sched_status(&adev->mes,
@@ -1963,12 +1798,6 @@ static int mes_v12_1_xcc_hw_init(struct amdgpu_ip_block *ip_block, int xcc_id)
amdgpu_mes_validate_fw_version(adev);
out:
- /*
- * Disable KIQ ring usage from the driver once MES is enabled.
- * MES uses KIQ ring exclusively so driver cannot access KIQ ring
- * with MES enabled.
- */
- adev->gfx.kiq[xcc_id].ring.sched.ready = false;
adev->mes.ring[MES_PIPE_INST(xcc_id, 0)].sched.ready = true;
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
index bdfd2917e3ca..ad24441776d2 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
@@ -22,6 +22,7 @@
*/
#include "amdgpu.h"
#include "nbio_v7_9.h"
+#include "amdgpu_ip.h"
#include "amdgpu_ras.h"
#include "nbio/nbio_7_9_0_offset.h"
@@ -535,7 +536,7 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device
RAS_CNTLR_INTERRUPT_CLEAR, 1);
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl);
- if (!ras->disable_ras_err_cnt_harvest) {
+ if (ras && !ras->disable_ras_err_cnt_harvest && obj) {
/*
* clear error status after ras_controller_intr
* according to hw team and count ue number
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index 657ef6c93c61..6b64cf83ee5c 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "vi.h"
#include "vid.h"
@@ -223,14 +224,14 @@ static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -350,18 +351,6 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev)
}
/**
- * sdma_v2_4_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues (VI).
- */
-static void sdma_v2_4_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v2_4_enable - stop the async dma engines
*
* @adev: amdgpu_device pointer
@@ -376,7 +365,6 @@ static void sdma_v2_4_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
sdma_v2_4_gfx_stop(adev);
- sdma_v2_4_rlc_stop(adev);
}
for (i = 0; i < adev->sdma.num_instances; i++) {
@@ -477,20 +465,6 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev)
return 0;
}
-/**
- * sdma_v2_4_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them (VI).
- * Returns 0 for success, error for failure.
- */
-static int sdma_v2_4_rlc_resume(struct amdgpu_device *adev)
-{
- /* XXX todo */
- return 0;
-}
-
/**
* sdma_v2_4_start - setup and start the async dma engines
@@ -511,9 +485,6 @@ static int sdma_v2_4_start(struct amdgpu_device *adev)
r = sdma_v2_4_gfx_resume(adev);
if (r)
return r;
- r = sdma_v2_4_rlc_resume(adev);
- if (r)
- return r;
return 0;
}
@@ -738,12 +709,13 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
static void sdma_v2_4_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -865,13 +837,8 @@ static int sdma_v2_4_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = false;
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- (i == 0) ? AMDGPU_SDMA_IRQ_INSTANCE0 :
- AMDGPU_SDMA_IRQ_INSTANCE1,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 9478dd034aff..6f7243370acb 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "vi.h"
#include "vid.h"
@@ -400,14 +401,14 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -527,18 +528,6 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev)
}
/**
- * sdma_v3_0_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues (VI).
- */
-static void sdma_v3_0_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v3_0_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -614,7 +603,6 @@ static void sdma_v3_0_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
sdma_v3_0_gfx_stop(adev);
- sdma_v3_0_rlc_stop(adev);
}
for (i = 0; i < adev->sdma.num_instances; i++) {
@@ -753,20 +741,6 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev)
}
/**
- * sdma_v3_0_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them (VI).
- * Returns 0 for success, error for failure.
- */
-static int sdma_v3_0_rlc_resume(struct amdgpu_device *adev)
-{
- /* XXX todo */
- return 0;
-}
-
-/**
* sdma_v3_0_start - setup and start the async dma engines
*
* @adev: amdgpu_device pointer
@@ -786,9 +760,6 @@ static int sdma_v3_0_start(struct amdgpu_device *adev)
r = sdma_v3_0_gfx_resume(adev);
if (r)
return r;
- r = sdma_v3_0_rlc_resume(adev);
- if (r)
- return r;
return 0;
}
@@ -1012,12 +983,13 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
static void sdma_v3_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1146,7 +1118,6 @@ static int sdma_v3_0_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
if (!amdgpu_sriov_vf(adev)) {
ring->use_doorbell = true;
ring->doorbell_index = adev->doorbell_index.sdma_engine[i];
@@ -1154,11 +1125,7 @@ static int sdma_v3_0_sw_init(struct amdgpu_ip_block *ip_block)
ring->use_pollmem = true;
}
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- (i == 0) ? AMDGPU_SDMA_IRQ_INSTANCE0 :
- AMDGPU_SDMA_IRQ_INSTANCE1,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
@@ -1234,13 +1201,11 @@ static int sdma_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
static int sdma_v3_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
- u32 srbm_soft_reset = 0;
+ u32 srbm_soft_reset;
u32 tmp;
- if (!adev->sdma.srbm_soft_reset)
- return 0;
-
- srbm_soft_reset = adev->sdma.srbm_soft_reset;
+ srbm_soft_reset = SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK |
+ SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 9d7d919a5aa1..902d31300326 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "sdma0/sdma0_4_2_offset.h"
@@ -783,14 +784,14 @@ static void sdma_v4_0_page_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -934,18 +935,6 @@ static void sdma_v4_0_gfx_enable(struct amdgpu_device *adev, bool enable)
}
/**
- * sdma_v4_0_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues (VEGA10).
- */
-static void sdma_v4_0_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v4_0_page_stop - stop the page async dma engines
*
* @adev: amdgpu_device pointer
@@ -1047,7 +1036,6 @@ static void sdma_v4_0_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
sdma_v4_0_gfx_enable(adev, enable);
- sdma_v4_0_rlc_stop(adev);
if (adev->sdma.has_page_queue)
sdma_v4_0_page_stop(adev);
}
@@ -1313,21 +1301,6 @@ static void sdma_v4_0_init_pg(struct amdgpu_device *adev)
}
/**
- * sdma_v4_0_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them (VEGA10).
- * Returns 0 for success, error for failure.
- */
-static int sdma_v4_0_rlc_resume(struct amdgpu_device *adev)
-{
- sdma_v4_0_init_pg(adev);
-
- return 0;
-}
-
-/**
* sdma_v4_0_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -1426,9 +1399,7 @@ static int sdma_v4_0_start(struct amdgpu_device *adev)
sdma_v4_0_ctx_switch_enable(adev, true);
sdma_v4_0_enable(adev, true);
} else {
- r = sdma_v4_0_rlc_resume(adev);
- if (r)
- return r;
+ sdma_v4_0_init_pg(adev);
}
for (i = 0; i < adev->sdma.num_instances; i++) {
@@ -1672,12 +1643,13 @@ static void sdma_v4_0_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v4_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1858,7 +1830,6 @@ static int sdma_v4_0_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
DRM_DEBUG("SDMA %d use_doorbell being set to: [%s]\n", i,
@@ -1878,16 +1849,12 @@ static int sdma_v4_0_sw_init(struct amdgpu_ip_block *ip_block)
else
ring->vm_hub = AMDGPU_MMHUB0(0);
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
if (adev->sdma.has_page_queue) {
ring = &adev->sdma.instance[i].page;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
/* paging queue use same doorbell index/routing as gfx queue
@@ -1915,11 +1882,7 @@ static int sdma_v4_0_sw_init(struct amdgpu_ip_block *ip_block)
else
ring->vm_hub = AMDGPU_MMHUB0(0);
- sprintf(ring->name, "page%d", i);
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "page%d", i);
if (r)
return r;
}
@@ -2051,13 +2014,6 @@ static int sdma_v4_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
-static int sdma_v4_0_soft_reset(struct amdgpu_ip_block *ip_block)
-{
- /* todo */
-
- return 0;
-}
-
static int sdma_v4_0_set_trap_irq_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned type,
@@ -2403,7 +2359,6 @@ const struct amd_ip_funcs sdma_v4_0_ip_funcs = {
.suspend = sdma_v4_0_suspend,
.resume = sdma_v4_0_resume,
.wait_for_idle = sdma_v4_0_wait_for_idle,
- .soft_reset = sdma_v4_0_soft_reset,
.set_clockgating_state = sdma_v4_0_set_clockgating_state,
.set_powergating_state = sdma_v4_0_set_powergating_state,
.get_clockgating_state = sdma_v4_0_get_clockgating_state,
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
index 461f8b220a3e..df788361e865 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
@@ -27,9 +27,11 @@
#include <linux/pci.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_xcp.h"
#include "amdgpu_ucode.h"
#include "amdgpu_trace.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_reset.h"
#include "sdma/sdma_4_4_2_offset.h"
@@ -348,14 +350,14 @@ static void sdma_v4_4_2_page_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v4_4_2_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -521,20 +523,6 @@ static void sdma_v4_4_2_inst_gfx_stop(struct amdgpu_device *adev,
}
/**
- * sdma_v4_4_2_inst_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- * @inst_mask: mask of dma engine instances to be disabled
- *
- * Stop the compute async dma queues.
- */
-static void sdma_v4_4_2_inst_rlc_stop(struct amdgpu_device *adev,
- uint32_t inst_mask)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v4_4_2_inst_page_stop - stop the page async dma engines
*
* @adev: amdgpu_device pointer
@@ -632,7 +620,6 @@ static void sdma_v4_4_2_inst_enable(struct amdgpu_device *adev, bool enable,
if (!enable) {
sdma_v4_4_2_inst_gfx_stop(adev, inst_mask);
- sdma_v4_4_2_inst_rlc_stop(adev, inst_mask);
if (adev->sdma.has_page_queue)
sdma_v4_4_2_inst_page_stop(adev, inst_mask);
@@ -675,12 +662,11 @@ static uint32_t sdma_v4_4_2_rb_cntl(struct amdgpu_ring *ring, uint32_t rb_cntl)
*
* @adev: amdgpu_device pointer
* @i: instance to resume
- * @restore: used to restore wptr when restart
*
* Set up the gfx DMA ring buffers and enable them.
* Returns 0 for success, error for failure.
*/
-static void sdma_v4_4_2_gfx_resume(struct amdgpu_device *adev, unsigned int i, bool restore)
+static void sdma_v4_4_2_gfx_resume(struct amdgpu_device *adev, unsigned int i)
{
struct amdgpu_ring *ring = &adev->sdma.instance[i].ring;
u32 rb_cntl, ib_cntl, wptr_poll_cntl;
@@ -688,7 +674,6 @@ static void sdma_v4_4_2_gfx_resume(struct amdgpu_device *adev, unsigned int i, b
u32 doorbell;
u32 doorbell_offset;
u64 wptr_gpu_addr;
- u64 rwptr;
wb_offset = (ring->rptr_offs * 4);
@@ -708,32 +693,16 @@ static void sdma_v4_4_2_gfx_resume(struct amdgpu_device *adev, unsigned int i, b
WREG32_SDMA(i, regSDMA_GFX_RB_BASE, ring->gpu_addr >> 8);
WREG32_SDMA(i, regSDMA_GFX_RB_BASE_HI, ring->gpu_addr >> 40);
- if (!restore)
- ring->wptr = 0;
+ ring->wptr = 0;
/* before programing wptr to a less value, need set minor_ptr_update first */
WREG32_SDMA(i, regSDMA_GFX_MINOR_PTR_UPDATE, 1);
- /* For the guilty queue, set RPTR to the current wptr to skip bad commands,
- * It is not a guilty queue, restore cache_rptr and continue execution.
- */
- if (adev->sdma.instance[i].gfx_guilty)
- rwptr = ring->wptr;
- else
- rwptr = ring->cached_rptr;
-
/* Initialize the ring buffer's read and write pointers */
- if (restore) {
- WREG32_SDMA(i, regSDMA_GFX_RB_RPTR, lower_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_GFX_RB_RPTR_HI, upper_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_GFX_RB_WPTR, lower_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_GFX_RB_WPTR_HI, upper_32_bits(rwptr << 2));
- } else {
- WREG32_SDMA(i, regSDMA_GFX_RB_RPTR, 0);
- WREG32_SDMA(i, regSDMA_GFX_RB_RPTR_HI, 0);
- WREG32_SDMA(i, regSDMA_GFX_RB_WPTR, 0);
- WREG32_SDMA(i, regSDMA_GFX_RB_WPTR_HI, 0);
- }
+ WREG32_SDMA(i, regSDMA_GFX_RB_RPTR, 0);
+ WREG32_SDMA(i, regSDMA_GFX_RB_RPTR_HI, 0);
+ WREG32_SDMA(i, regSDMA_GFX_RB_WPTR, 0);
+ WREG32_SDMA(i, regSDMA_GFX_RB_WPTR_HI, 0);
doorbell = RREG32_SDMA(i, regSDMA_GFX_DOORBELL);
doorbell_offset = RREG32_SDMA(i, regSDMA_GFX_DOORBELL_OFFSET);
@@ -786,7 +755,7 @@ static void sdma_v4_4_2_gfx_resume(struct amdgpu_device *adev, unsigned int i, b
* Set up the page DMA ring buffers and enable them.
* Returns 0 for success, error for failure.
*/
-static void sdma_v4_4_2_page_resume(struct amdgpu_device *adev, unsigned int i, bool restore)
+static void sdma_v4_4_2_page_resume(struct amdgpu_device *adev, unsigned int i)
{
struct amdgpu_ring *ring = &adev->sdma.instance[i].page;
u32 rb_cntl, ib_cntl, wptr_poll_cntl;
@@ -794,7 +763,6 @@ static void sdma_v4_4_2_page_resume(struct amdgpu_device *adev, unsigned int i,
u32 doorbell;
u32 doorbell_offset;
u64 wptr_gpu_addr;
- u64 rwptr;
wb_offset = (ring->rptr_offs * 4);
@@ -802,26 +770,11 @@ static void sdma_v4_4_2_page_resume(struct amdgpu_device *adev, unsigned int i,
rb_cntl = sdma_v4_4_2_rb_cntl(ring, rb_cntl);
WREG32_SDMA(i, regSDMA_PAGE_RB_CNTL, rb_cntl);
- /* For the guilty queue, set RPTR to the current wptr to skip bad commands,
- * It is not a guilty queue, restore cache_rptr and continue execution.
- */
- if (adev->sdma.instance[i].page_guilty)
- rwptr = ring->wptr;
- else
- rwptr = ring->cached_rptr;
-
/* Initialize the ring buffer's read and write pointers */
- if (restore) {
- WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR, lower_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR_HI, upper_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR, lower_32_bits(rwptr << 2));
- WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR_HI, upper_32_bits(rwptr << 2));
- } else {
- WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR, 0);
- WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR_HI, 0);
- WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR, 0);
- WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR_HI, 0);
- }
+ WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR, 0);
+ WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR_HI, 0);
+ WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR, 0);
+ WREG32_SDMA(i, regSDMA_PAGE_RB_WPTR_HI, 0);
/* set the wb address whether it's enabled or not */
WREG32_SDMA(i, regSDMA_PAGE_RB_RPTR_ADDR_HI,
@@ -835,8 +788,7 @@ static void sdma_v4_4_2_page_resume(struct amdgpu_device *adev, unsigned int i,
WREG32_SDMA(i, regSDMA_PAGE_RB_BASE, ring->gpu_addr >> 8);
WREG32_SDMA(i, regSDMA_PAGE_RB_BASE_HI, ring->gpu_addr >> 40);
- if (!restore)
- ring->wptr = 0;
+ ring->wptr = 0;
/* before programing wptr to a less value, need set minor_ptr_update first */
WREG32_SDMA(i, regSDMA_PAGE_MINOR_PTR_UPDATE, 1);
@@ -889,23 +841,6 @@ static void sdma_v4_4_2_init_pg(struct amdgpu_device *adev)
}
/**
- * sdma_v4_4_2_inst_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- * @inst_mask: mask of dma engine instances to be enabled
- *
- * Set up the compute DMA queues and enable them.
- * Returns 0 for success, error for failure.
- */
-static int sdma_v4_4_2_inst_rlc_resume(struct amdgpu_device *adev,
- uint32_t inst_mask)
-{
- sdma_v4_4_2_init_pg(adev);
-
- return 0;
-}
-
-/**
* sdma_v4_4_2_inst_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -991,9 +926,9 @@ static int sdma_v4_4_2_inst_start(struct amdgpu_device *adev,
uint32_t temp;
WREG32_SDMA(i, regSDMA_SEM_WAIT_FAIL_TIMER_CNTL, 0);
- sdma_v4_4_2_gfx_resume(adev, i, restore);
+ sdma_v4_4_2_gfx_resume(adev, i);
if (adev->sdma.has_page_queue)
- sdma_v4_4_2_page_resume(adev, i, restore);
+ sdma_v4_4_2_page_resume(adev, i);
/* set utc l1 enable flag always to 1 */
temp = RREG32_SDMA(i, regSDMA_CNTL);
@@ -1019,9 +954,7 @@ static int sdma_v4_4_2_inst_start(struct amdgpu_device *adev,
sdma_v4_4_2_inst_ctx_switch_enable(adev, true, inst_mask);
sdma_v4_4_2_inst_enable(adev, true, inst_mask);
} else {
- r = sdma_v4_4_2_inst_rlc_resume(adev, inst_mask);
- if (r)
- return r;
+ sdma_v4_4_2_init_pg(adev);
}
tmp_mask = inst_mask;
@@ -1266,12 +1199,13 @@ static void sdma_v4_4_2_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v4_4_2_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1478,13 +1412,9 @@ static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
mutex_init(&adev->sdma.instance[i].engine_reset_mutex);
- /* Initialize guilty flags for GFX and PAGE queues */
- adev->sdma.instance[i].gfx_guilty = false;
- adev->sdma.instance[i].page_guilty = false;
adev->sdma.instance[i].funcs = &sdma_v4_4_2_sdma_funcs;
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
aid_id = adev->sdma.instance[i].aid_id;
@@ -1495,18 +1425,13 @@ static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block)
ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1;
ring->vm_hub = AMDGPU_MMHUB0(aid_id);
ring->no_user_submission = adev->sdma.no_user_submission;
-
- sprintf(ring->name, "sdma%d.%d", aid_id,
- i % adev->sdma.num_inst_per_aid);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d.%d", aid_id,
+ i % adev->sdma.num_inst_per_aid);
if (r)
return r;
if (adev->sdma.has_page_queue) {
ring = &adev->sdma.instance[i].page;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
/* doorbell index of page queue is assigned right after
@@ -1515,13 +1440,9 @@ static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block)
ring->doorbell_index =
(adev->doorbell_index.sdma_engine[i] + 1) << 1;
ring->vm_hub = AMDGPU_MMHUB0(aid_id);
-
- sprintf(ring->name, "page%d.%d", aid_id,
- i % adev->sdma.num_inst_per_aid);
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "page%d.%d",
+ aid_id,
+ i % adev->sdma.num_inst_per_aid);
if (r)
return r;
}
@@ -1651,65 +1572,14 @@ static int sdma_v4_4_2_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
-static int sdma_v4_4_2_soft_reset(struct amdgpu_ip_block *ip_block)
-{
- /* todo */
-
- return 0;
-}
-
-static bool sdma_v4_4_2_is_queue_selected(struct amdgpu_device *adev, uint32_t instance_id, bool is_page_queue)
-{
- uint32_t reg_offset = is_page_queue ? regSDMA_PAGE_CONTEXT_STATUS : regSDMA_GFX_CONTEXT_STATUS;
- uint32_t context_status = RREG32(sdma_v4_4_2_get_reg_offset(adev, instance_id, reg_offset));
-
- /* Check if the SELECTED bit is set */
- return (context_status & SDMA_GFX_CONTEXT_STATUS__SELECTED_MASK) != 0;
-}
-
-static int sdma_v4_4_2_reset_queue(struct amdgpu_ring *ring,
- unsigned int vmid,
- struct amdgpu_fence *timedout_fence)
-{
- struct amdgpu_device *adev = ring->adev;
- u32 id = ring->me;
- int r;
-
- amdgpu_amdkfd_suspend(adev, true);
- r = amdgpu_sdma_reset_engine(adev, id, false);
- amdgpu_amdkfd_resume(adev, true);
- return r;
-}
-
static int sdma_v4_4_2_stop_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
- u32 instance_id = ring->me;
u32 inst_mask;
- uint64_t rptr;
if (amdgpu_sriov_vf(adev))
return -EINVAL;
- /* Check if this queue is the guilty one */
- adev->sdma.instance[instance_id].gfx_guilty =
- sdma_v4_4_2_is_queue_selected(adev, instance_id, false);
- if (adev->sdma.has_page_queue)
- adev->sdma.instance[instance_id].page_guilty =
- sdma_v4_4_2_is_queue_selected(adev, instance_id, true);
-
- /* Cache the rptr before reset, after the reset,
- * all of the registers will be reset to 0
- */
- rptr = amdgpu_ring_get_rptr(ring);
- ring->cached_rptr = rptr;
- /* Cache the rptr for the page queue if it exists */
- if (adev->sdma.has_page_queue) {
- struct amdgpu_ring *page_ring = &adev->sdma.instance[instance_id].page;
- rptr = amdgpu_ring_get_rptr(page_ring);
- page_ring->cached_rptr = rptr;
- }
-
/* stop queue */
inst_mask = 1 << ring->me;
sdma_v4_4_2_inst_gfx_stop(adev, inst_mask);
@@ -2109,7 +1979,6 @@ const struct amd_ip_funcs sdma_v4_4_2_ip_funcs = {
.suspend = sdma_v4_4_2_suspend,
.resume = sdma_v4_4_2_resume,
.wait_for_idle = sdma_v4_4_2_wait_for_idle,
- .soft_reset = sdma_v4_4_2_soft_reset,
.set_clockgating_state = sdma_v4_4_2_set_clockgating_state,
.set_powergating_state = sdma_v4_4_2_set_powergating_state,
.get_clockgating_state = sdma_v4_4_2_get_clockgating_state,
@@ -2146,7 +2015,7 @@ static const struct amdgpu_ring_funcs sdma_v4_4_2_ring_funcs = {
.emit_wreg = sdma_v4_4_2_ring_emit_wreg,
.emit_reg_wait = sdma_v4_4_2_ring_emit_reg_wait,
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
- .reset = sdma_v4_4_2_reset_queue,
+ .reset = amdgpu_sdma_reset_queue_legacy,
};
static const struct amdgpu_ring_funcs sdma_v4_4_2_page_ring_funcs = {
@@ -2178,7 +2047,7 @@ static const struct amdgpu_ring_funcs sdma_v4_4_2_page_ring_funcs = {
.emit_wreg = sdma_v4_4_2_ring_emit_wreg,
.emit_reg_wait = sdma_v4_4_2_ring_emit_reg_wait,
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
- .reset = sdma_v4_4_2_reset_queue,
+ .reset = amdgpu_sdma_reset_queue_legacy,
};
static void sdma_v4_4_2_set_ring_funcs(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index 97fee70dc2f6..c6349f0e632f 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "gc/gc_10_1_0_offset.h"
@@ -406,14 +407,14 @@ static void sdma_v5_0_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v5_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -575,18 +576,6 @@ static void sdma_v5_0_gfx_stop(struct amdgpu_device *adev, uint32_t inst_mask)
}
/**
- * sdma_v5_0_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues (NAVI10).
- */
-static void sdma_v5_0_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v5_0_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -661,7 +650,6 @@ static void sdma_v5_0_enable(struct amdgpu_device *adev, bool enable)
inst_mask = GENMASK(adev->sdma.num_instances - 1, 0);
if (!enable) {
sdma_v5_0_gfx_stop(adev, 1 << inst_mask);
- sdma_v5_0_rlc_stop(adev);
}
if (amdgpu_sriov_vf(adev))
@@ -859,19 +847,6 @@ static int sdma_v5_0_gfx_resume(struct amdgpu_device *adev)
}
/**
- * sdma_v5_0_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them (NAVI10).
- * Returns 0 for success, error for failure.
- */
-static int sdma_v5_0_rlc_resume(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-/**
* sdma_v5_0_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -951,7 +926,6 @@ static int sdma_v5_0_start(struct amdgpu_device *adev)
r = sdma_v5_0_gfx_resume(adev);
if (r)
return r;
- r = sdma_v5_0_rlc_resume(adev);
return r;
}
@@ -1240,12 +1214,13 @@ static void sdma_v5_0_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v5_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 0x7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1411,7 +1386,6 @@ static int sdma_v5_0_sw_init(struct amdgpu_ip_block *ip_block)
mutex_init(&adev->sdma.instance[i].engine_reset_mutex);
adev->sdma.instance[i].funcs = &sdma_v5_0_sdma_funcs;
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
DRM_DEBUG("SDMA %d use_doorbell being set to: [%s]\n", i,
@@ -1422,11 +1396,7 @@ static int sdma_v5_0_sw_init(struct amdgpu_ip_block *ip_block)
: (adev->doorbell_index.sdma_engine[1] << 1); // get DWORD offset
ring->vm_hub = AMDGPU_GFXHUB(0);
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- (i == 0) ? AMDGPU_SDMA_IRQ_INSTANCE0 :
- AMDGPU_SDMA_IRQ_INSTANCE1,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
@@ -1522,36 +1492,6 @@ static int sdma_v5_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
-static int sdma_v5_0_soft_reset(struct amdgpu_ip_block *ip_block)
-{
- /* todo */
-
- return 0;
-}
-
-static int sdma_v5_0_reset_queue(struct amdgpu_ring *ring,
- unsigned int vmid,
- struct amdgpu_fence *timedout_fence)
-{
- struct amdgpu_device *adev = ring->adev;
- int r;
-
- if (ring->me >= adev->sdma.num_instances) {
- dev_err(adev->dev, "sdma instance not found\n");
- return -EINVAL;
- }
-
- amdgpu_ring_reset_helper_begin(ring, timedout_fence);
-
- amdgpu_amdkfd_suspend(adev, true);
- r = amdgpu_sdma_reset_engine(adev, ring->me, true);
- amdgpu_amdkfd_resume(adev, true);
- if (r)
- return r;
-
- return amdgpu_ring_reset_helper_end(ring, timedout_fence);
-}
-
static int sdma_v5_0_stop_queue(struct amdgpu_ring *ring)
{
u32 f32_cntl, freeze, cntl, stat1_reg;
@@ -1624,11 +1564,9 @@ static int sdma_v5_0_ring_preempt_ib(struct amdgpu_ring *ring)
{
int i, r = 0;
struct amdgpu_device *adev = ring->adev;
- u32 index = 0;
u64 sdma_gfx_preempt;
- amdgpu_sdma_get_index_from_ring(ring, &index);
- if (index == 0)
+ if (ring->me == 0)
sdma_gfx_preempt = mmSDMA0_GFX_PREEMPT;
else
sdma_gfx_preempt = mmSDMA1_GFX_PREEMPT;
@@ -1906,7 +1844,6 @@ static const struct amd_ip_funcs sdma_v5_0_ip_funcs = {
.suspend = sdma_v5_0_suspend,
.resume = sdma_v5_0_resume,
.wait_for_idle = sdma_v5_0_wait_for_idle,
- .soft_reset = sdma_v5_0_soft_reset,
.set_clockgating_state = sdma_v5_0_set_clockgating_state,
.set_powergating_state = sdma_v5_0_set_powergating_state,
.get_clockgating_state = sdma_v5_0_get_clockgating_state,
@@ -1948,7 +1885,7 @@ static const struct amdgpu_ring_funcs sdma_v5_0_ring_funcs = {
.emit_reg_write_reg_wait = sdma_v5_0_ring_emit_reg_write_reg_wait,
.init_cond_exec = sdma_v5_0_ring_init_cond_exec,
.preempt_ib = sdma_v5_0_ring_preempt_ib,
- .reset = sdma_v5_0_reset_queue,
+ .reset = amdgpu_sdma_reset_queue_legacy,
};
static void sdma_v5_0_set_ring_funcs(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
index 35cdf6c149f8..683f27c27665 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "gc/gc_10_3_0_offset.h"
@@ -254,14 +255,14 @@ static void sdma_v5_2_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v5_2_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -425,18 +426,6 @@ static void sdma_v5_2_gfx_stop(struct amdgpu_device *adev, uint32_t inst_mask)
}
/**
- * sdma_v5_2_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues.
- */
-static void sdma_v5_2_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v5_2_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -510,7 +499,6 @@ static void sdma_v5_2_enable(struct amdgpu_device *adev, bool enable)
inst_mask = GENMASK(adev->sdma.num_instances - 1, 0);
if (!enable) {
sdma_v5_2_gfx_stop(adev, inst_mask);
- sdma_v5_2_rlc_stop(adev);
}
if (!amdgpu_sriov_vf(adev)) {
@@ -706,19 +694,6 @@ static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev)
}
/**
- * sdma_v5_2_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them.
- * Returns 0 for success, error for failure.
- */
-static int sdma_v5_2_rlc_resume(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-/**
* sdma_v5_2_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -851,7 +826,6 @@ static int sdma_v5_2_start(struct amdgpu_device *adev)
r = sdma_v5_2_gfx_resume(adev);
if (r)
return r;
- r = sdma_v5_2_rlc_resume(adev);
return r;
}
@@ -1141,12 +1115,13 @@ static void sdma_v5_2_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v5_2_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 0x7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1331,7 +1306,6 @@ static int sdma_v5_2_sw_init(struct amdgpu_ip_block *ip_block)
mutex_init(&adev->sdma.instance[i].engine_reset_mutex);
adev->sdma.instance[i].funcs = &sdma_v5_2_sdma_funcs;
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
@@ -1342,10 +1316,7 @@ static int sdma_v5_2_sw_init(struct amdgpu_ip_block *ip_block)
(adev->doorbell_index.sdma_engine[i] << 1); //get DWORD offset
ring->vm_hub = AMDGPU_GFXHUB(0);
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
@@ -1441,29 +1412,6 @@ static int sdma_v5_2_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
-static int sdma_v5_2_reset_queue(struct amdgpu_ring *ring,
- unsigned int vmid,
- struct amdgpu_fence *timedout_fence)
-{
- struct amdgpu_device *adev = ring->adev;
- int r;
-
- if (ring->me >= adev->sdma.num_instances) {
- dev_err(adev->dev, "sdma instance not found\n");
- return -EINVAL;
- }
-
- amdgpu_ring_reset_helper_begin(ring, timedout_fence);
-
- amdgpu_amdkfd_suspend(adev, true);
- r = amdgpu_sdma_reset_engine(adev, ring->me, true);
- amdgpu_amdkfd_resume(adev, true);
- if (r)
- return r;
-
- return amdgpu_ring_reset_helper_end(ring, timedout_fence);
-}
-
static int sdma_v5_2_stop_queue(struct amdgpu_ring *ring)
{
u32 f32_cntl, freeze, cntl, stat1_reg;
@@ -1539,12 +1487,10 @@ static int sdma_v5_2_ring_preempt_ib(struct amdgpu_ring *ring)
{
int i, r = 0;
struct amdgpu_device *adev = ring->adev;
- u32 index = 0;
u64 sdma_gfx_preempt;
- amdgpu_sdma_get_index_from_ring(ring, &index);
- sdma_gfx_preempt =
- sdma_v5_2_get_reg_offset(adev, index, mmSDMA0_GFX_PREEMPT);
+ sdma_gfx_preempt = sdma_v5_2_get_reg_offset(adev, ring->me,
+ mmSDMA0_GFX_PREEMPT);
/* assert preemption condition */
amdgpu_ring_set_preempt_cond_exec(ring, false);
@@ -1956,7 +1902,7 @@ static const struct amdgpu_ring_funcs sdma_v5_2_ring_funcs = {
.emit_reg_write_reg_wait = sdma_v5_2_ring_emit_reg_write_reg_wait,
.init_cond_exec = sdma_v5_2_ring_init_cond_exec,
.preempt_ib = sdma_v5_2_ring_preempt_ib,
- .reset = sdma_v5_2_reset_queue,
+ .reset = amdgpu_sdma_reset_queue_legacy,
};
static void sdma_v5_2_set_ring_funcs(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index 0b64eb5b32e9..16649dba6329 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "gc/gc_11_0_0_offset.h"
@@ -242,14 +243,14 @@ static void sdma_v6_0_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v6_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/*
@@ -408,18 +409,6 @@ static void sdma_v6_0_gfx_stop(struct amdgpu_device *adev)
}
/**
- * sdma_v6_0_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues.
- */
-static void sdma_v6_0_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v6_0_ctxempty_int_enable - enable or disable context empty interrupts
*
* @adev: amdgpu_device pointer
@@ -457,7 +446,6 @@ static void sdma_v6_0_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
sdma_v6_0_gfx_stop(adev);
- sdma_v6_0_rlc_stop(adev);
}
if (amdgpu_sriov_vf(adev))
@@ -643,19 +631,6 @@ static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev)
}
/**
- * sdma_v6_0_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them.
- * Returns 0 for success, error for failure.
- */
-static int sdma_v6_0_rlc_resume(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-/**
* sdma_v6_0_load_microcode - load the sDMA ME ucode
*
* @adev: amdgpu_device pointer
@@ -832,7 +807,6 @@ static int sdma_v6_0_start(struct amdgpu_device *adev)
r = sdma_v6_0_gfx_resume(adev);
if (r)
return r;
- r = sdma_v6_0_rlc_resume(adev);
return r;
}
@@ -1131,12 +1105,13 @@ static void sdma_v6_0_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v6_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 0x7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1335,7 +1310,6 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
ring->no_user_submission = adev->sdma.no_user_submission;
@@ -1347,11 +1321,8 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
(adev->doorbell_index.sdma_engine[i] << 1); // get DWORD offset
ring->vm_hub = AMDGPU_GFXHUB(0);
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
@@ -1515,12 +1486,10 @@ static int sdma_v6_0_ring_preempt_ib(struct amdgpu_ring *ring)
{
int i, r = 0;
struct amdgpu_device *adev = ring->adev;
- u32 index = 0;
u64 sdma_gfx_preempt;
- amdgpu_sdma_get_index_from_ring(ring, &index);
- sdma_gfx_preempt =
- sdma_v6_0_get_reg_offset(adev, index, regSDMA0_QUEUE0_PREEMPT);
+ sdma_gfx_preempt = sdma_v6_0_get_reg_offset(adev, ring->me,
+ regSDMA0_QUEUE0_PREEMPT);
/* assert preemption condition */
amdgpu_ring_set_preempt_cond_exec(ring, false);
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index c55c941b82cf..edd9c437f7cb 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "gc/gc_12_0_0_offset.h"
@@ -244,14 +245,14 @@ static void sdma_v7_0_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v7_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -410,18 +411,6 @@ static void sdma_v7_0_gfx_stop(struct amdgpu_device *adev)
}
/**
- * sdma_v7_0_rlc_stop - stop the compute async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Stop the compute async dma queues.
- */
-static void sdma_v7_0_rlc_stop(struct amdgpu_device *adev)
-{
- /* XXX todo */
-}
-
-/**
* sdma_v7_0_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -448,7 +437,6 @@ static void sdma_v7_0_enable(struct amdgpu_device *adev, bool enable)
if (!enable) {
sdma_v7_0_gfx_stop(adev);
- sdma_v7_0_rlc_stop(adev);
}
if (amdgpu_sriov_vf(adev))
@@ -643,19 +631,6 @@ static int sdma_v7_0_gfx_resume(struct amdgpu_device *adev)
}
-/**
- * sdma_v7_0_rlc_resume - setup and start the async dma engines
- *
- * @adev: amdgpu_device pointer
- *
- * Set up the compute DMA queues and enable them.
- * Returns 0 for success, error for failure.
- */
-static int sdma_v7_0_rlc_resume(struct amdgpu_device *adev)
-{
- return 0;
-}
-
static void sdma_v12_0_free_ucode_buffer(struct amdgpu_device *adev)
{
int i;
@@ -878,7 +853,6 @@ static int sdma_v7_0_start(struct amdgpu_device *adev)
r = sdma_v7_0_gfx_resume(adev);
if (r)
return r;
- r = sdma_v7_0_rlc_resume(adev);
return r;
}
@@ -1178,12 +1152,13 @@ static void sdma_v7_0_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v7_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 0x7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1347,7 +1322,6 @@ static int sdma_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
ring->no_user_submission = adev->sdma.no_user_submission;
@@ -1359,11 +1333,7 @@ static int sdma_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
(adev->doorbell_index.sdma_engine[i] << 1); // get DWORD offset
ring->vm_hub = AMDGPU_GFXHUB(0);
- sprintf(ring->name, "sdma%d", i);
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d", i);
if (r)
return r;
}
@@ -1497,12 +1467,10 @@ static int sdma_v7_0_ring_preempt_ib(struct amdgpu_ring *ring)
{
int i, r = 0;
struct amdgpu_device *adev = ring->adev;
- u32 index = 0;
u64 sdma_gfx_preempt;
- amdgpu_sdma_get_index_from_ring(ring, &index);
- sdma_gfx_preempt =
- sdma_v7_0_get_reg_offset(adev, index, regSDMA0_QUEUE0_PREEMPT);
+ sdma_gfx_preempt = sdma_v7_0_get_reg_offset(adev, ring->me,
+ regSDMA0_QUEUE0_PREEMPT);
/* assert preemption condition */
amdgpu_ring_set_preempt_cond_exec(ring, false);
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
index 0f30eb503c2a..321c67e01443 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
@@ -28,6 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_ucode.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_trace.h"
#include "gc/gc_12_1_0_offset.h"
@@ -238,14 +239,14 @@ static void sdma_v7_1_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v7_1_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
- int i;
+ const u32 nop = ring->funcs->nop;
- for (i = 0; i < count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
- amdgpu_ring_write(ring, ring->funcs->nop |
- SDMA_PKT_NOP_HEADER_COUNT(count - 1));
- else
- amdgpu_ring_write(ring, ring->funcs->nop);
+ if (count && sdma->burst_nop) {
+ --count;
+ amdgpu_ring_write(ring, nop | SDMA_PKT_NOP_HEADER_COUNT(count));
+ }
+
+ amdgpu_ring_fill(ring, nop, count);
}
/**
@@ -1161,12 +1162,13 @@ static void sdma_v7_1_vm_set_pte_pde(struct amdgpu_ib *ib,
static void sdma_v7_1_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
+ const bool burst_nop = sdma->burst_nop;
u32 pad_count;
int i;
pad_count = (-ib->length_dw) & 0x7;
for (i = 0; i < pad_count; i++)
- if (sdma && sdma->burst_nop && (i == 0))
+ if (i == 0 && burst_nop)
ib->ptr[ib->length_dw++] =
SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1);
@@ -1305,7 +1307,6 @@ static int sdma_v7_1_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
ring->no_user_submission = adev->sdma.no_user_submission;
@@ -1323,12 +1324,9 @@ static int sdma_v7_1_sw_init(struct amdgpu_ip_block *ip_block)
(adev->doorbell_index.sdma_engine[i] << 1); // get DWORD offset
ring->vm_hub = AMDGPU_GFXHUB(xcc_id);
- sprintf(ring->name, "sdma%d.%d", xcc_id,
- GET_INST(SDMA0, i) % adev->sdma.num_inst_per_xcc);
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->sdma.trap_irq,
- AMDGPU_SDMA_IRQ_INSTANCE0 + i,
- AMDGPU_RING_PRIO_DEFAULT, NULL);
+ r = amdgpu_sdma_ring_init(adev, ring, i, "sdma%d.%d", xcc_id,
+ GET_INST(SDMA0, i) %
+ adev->sdma.num_inst_per_xcc);
if (r)
return r;
}
@@ -1456,12 +1454,10 @@ static int sdma_v7_1_ring_preempt_ib(struct amdgpu_ring *ring)
{
int i, r = 0;
struct amdgpu_device *adev = ring->adev;
- u32 index = 0;
u64 sdma_gfx_preempt;
- amdgpu_sdma_get_index_from_ring(ring, &index);
- sdma_gfx_preempt =
- sdma_v7_1_get_reg_offset(adev, index, regSDMA0_SDMA_QUEUE0_PREEMPT);
+ sdma_gfx_preempt = sdma_v7_1_get_reg_offset(adev, ring->me,
+ regSDMA0_SDMA_QUEUE0_PREEMPT);
/* assert preemption condition */
amdgpu_ring_set_preempt_cond_exec(ring, false);
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index 3705a963e660..31ab701d45d3 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -600,12 +600,6 @@ static int si_dma_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
-static int si_dma_soft_reset(struct amdgpu_ip_block *ip_block)
-{
- drm_info(adev_to_drm(ip_block->adev), "si_dma_soft_reset --- not implemented !!!!!!!\n");
- return 0;
-}
-
static int si_dma_set_trap_irq_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src,
unsigned type,
@@ -732,7 +726,6 @@ static const struct amd_ip_funcs si_dma_ip_funcs = {
.suspend = si_dma_suspend,
.resume = si_dma_resume,
.wait_for_idle = si_dma_wait_for_idle,
- .soft_reset = si_dma_soft_reset,
.set_clockgating_state = si_dma_set_clockgating_state,
.set_powergating_state = si_dma_set_powergating_state,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15_common.h b/drivers/gpu/drm/amd/amdgpu/soc15_common.h
index 47e0329b6f3f..937d02ef7124 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15_common.h
+++ b/drivers/gpu/drm/amd/amdgpu/soc15_common.h
@@ -26,11 +26,9 @@
/* GET_INST returns the physical instance corresponding to a logical instance */
#define GET_INST(ip, inst) \
- (adev->ip_map.logical_to_dev_inst ? \
- adev->ip_map.logical_to_dev_inst(adev, ip##_HWIP, inst) : inst)
+ amdgpu_ip_map_logical_to_dev_inst(&adev->ip_map, ip##_HWIP, inst)
#define GET_MASK(ip, mask) \
- (adev->ip_map.logical_to_dev_mask ? \
- adev->ip_map.logical_to_dev_mask(adev, ip##_HWIP, mask) : mask)
+ amdgpu_ip_map_logical_to_dev_mask(&adev->ip_map, ip##_HWIP, mask)
/* Register Access Macros */
#define SOC15_REG_OFFSET(ip, inst, reg) (adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg)
diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
index 757da0a30fdc..28eca48c6596 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
@@ -1097,15 +1097,9 @@ static int soc_v1_0_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
if (adev->kfd.init_complete && !amdgpu_in_reset(adev))
flags |= AMDGPU_XCP_OPS_KFD;
- if (flags & AMDGPU_XCP_OPS_KFD) {
- ret = amdgpu_amdkfd_check_and_lock_kfd(adev);
- if (ret)
- goto out;
- }
-
ret = amdgpu_xcp_pre_partition_switch(xcp_mgr, flags);
if (ret)
- goto unlock;
+ goto out;
num_xcc_per_xcp = __soc_v1_0_get_xcc_per_xcp(xcp_mgr, mode);
if (adev->gfx.imu.funcs &&
@@ -1126,9 +1120,6 @@ static int soc_v1_0_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
ret = amdgpu_xcp_post_partition_switch(xcp_mgr, flags);
if (!ret)
__soc_v1_0_update_available_partition_mode(xcp_mgr);
-unlock:
- if (flags & AMDGPU_XCP_OPS_KFD)
- amdgpu_amdkfd_unlock_kfd(adev);
out:
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index c559213e442c..7d2b9e4b913a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -25,6 +25,7 @@
#include <drm/drm_drv.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "soc15.h"
#include "soc15d.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 732aaa1d8e67..10ef5616b2f5 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -25,6 +25,7 @@
#include <drm/drm_drv.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index e876733b754a..0f4f4d66e2e4 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "amdgpu_cs.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 60a5636c0073..4b7f7bbe18da 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "amdgpu_cs.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 3d28289bc4f1..2fa8f0d911d0 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -25,6 +25,7 @@
#include <drm/drm_drv.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 660dab262dfb..f30f80c1b07f 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "amdgpu_cs.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 08fca20b2c99..7b7c3bc9f046 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
index b3b83ad20103..09e553b8a657 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_vcn.h"
#include "amdgpu_pm.h"
#include "soc15.h"
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 1c1e7878a2a7..23db8dcb076d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -34,6 +34,7 @@
#include "kfd_svm.h"
#include "kfd_migrate.h"
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_xcp.h"
#define MQD_SIZE_ALIGNED 768
@@ -952,7 +953,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
svm_range_set_max_pages(kfd->adev);
- kfd->init_complete = true;
+ /* Release pairs with the acquire in kfd_init_apertures(). */
+ smp_store_release(&kfd->init_complete, true);
dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor,
kfd->adev->pdev->device);
@@ -977,7 +979,7 @@ out:
return kfd->init_complete;
}
-void kgd2kfd_device_exit(struct kfd_dev *kfd)
+void kgd2kfd_device_fini(struct kfd_dev *kfd)
{
if (kfd->init_complete) {
/* Cleanup KFD nodes */
@@ -991,6 +993,11 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
}
kfree(kfd);
+}
+
+void kgd2kfd_device_exit(struct kfd_dev *kfd)
+{
+ kgd2kfd_device_fini(kfd);
/* after remove a kfd device unlock kfd driver */
kgd2kfd_unlock_kfd(NULL);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 3ec6a73af22e..ace5609fbb4b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -797,10 +797,12 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
q->properties.type)];
if (qd && !mqd_mgr->restore_mqd) {
- pr_debug("restore_mqd not implemented for this GPU\n");
+ pr_debug("restore_mqd not implemented for queue type %d\n",
+ q->properties.type);
retval = -EOPNOTSUPP;
goto deallocate_vmid;
}
+
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
retval = allocate_hqd(dqm, q);
if (retval)
@@ -1504,6 +1506,67 @@ out:
return retval;
}
+static int clean_process_queues_cpsch(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd)
+{
+ struct queue *q;
+ struct kfd_process_device *pdd;
+ int retval = 0;
+
+ dqm_lock(dqm);
+ if (qpd->evicted++ > 0) /* already evicted, do nothing */
+ goto out;
+
+ pdd = qpd_to_pdd(qpd);
+
+ /* The debugger creates processes that temporarily have not acquired
+ * all VMs for all devices and has no VMs itself.
+ * Skip queue eviction on process eviction.
+ */
+ if (!pdd->drm_priv)
+ goto out;
+
+ pr_debug_ratelimited("Evicting process pid %d queues\n",
+ pdd->process->lead_thread->pid);
+
+ /* Mark all queues as evicted. Deactivate all active queues on
+ * the qpd.
+ */
+ list_for_each_entry(q, &qpd->queues_list, list) {
+ q->properties.is_evicted = true;
+ if (!q->properties.is_active)
+ continue;
+
+ q->properties.is_active = false;
+ decrement_queue_count(dqm, qpd, q);
+
+ dqm_evict_mqd_bo(dqm, q);
+ }
+
+ pdd->last_evict_timestamp = get_jiffies_64();
+
+ if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem)) {
+ retval = -EIO;
+ goto out;
+ }
+
+ retval = unmap_queues_cpsch(dqm,
+ KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES,
+ 0,
+ USE_DEFAULT_GRACE_PERIOD,
+ false);
+
+ if (!retval) {
+ dqm->dev->kfd2kgd->hqd_gfx_clean_fault(dqm->dev->adev);
+ retval = map_queues_cpsch(dqm);
+ }
+ up_read(&dqm->dev->adev->reset_domain->sem);
+
+out:
+ dqm_unlock(dqm);
+ return retval;
+}
+
static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
struct qcm_process_device *qpd)
{
@@ -2317,7 +2380,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
q->properties.type)];
if (qd && !mqd_mgr->restore_mqd) {
- pr_debug("restore_mqd not implemented for this GPU\n");
+ pr_debug("restore_mqd not implemented for queue type %d\n",
+ q->properties.type);
retval = -EOPNOTSUPP;
goto out_deallocate_doorbell;
}
@@ -2661,7 +2725,7 @@ static int reset_hung_queues_sdma(struct device_queue_manager *dqm)
continue;
/* Reset engine and check. */
- if (amdgpu_sdma_reset_engine(dqm->dev->adev, i, false) ||
+ if (amdgpu_sdma_reset_engine(dqm->dev->adev, i) ||
dqm->dev->kfd2kgd->hqd_sdma_get_doorbell(dqm->dev->adev, i, j) ||
!set_sdma_queue_as_reset(dqm, doorbell_off)) {
r = -ENOTRECOVERABLE;
@@ -3347,6 +3411,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
dqm->ops.checkpoint_mqd = checkpoint_mqd;
dqm->ops.set_perfcount = set_perfcount;
+ dqm->ops.clean_process_queues_cpsch = clean_process_queues_cpsch;
break;
case KFD_SCHED_POLICY_NO_HWS:
/* initialize dqm for no cp scheduling */
@@ -3368,6 +3433,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
dqm->ops.checkpoint_mqd = checkpoint_mqd;
dqm->ops.set_perfcount = set_perfcount;
+ dqm->ops.clean_process_queues_cpsch = clean_process_queues_cpsch;
break;
default:
dev_err(dev->adev->dev, "Invalid scheduling policy %d\n", dqm->sched_policy);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index 21cf3c16f3f9..f55f313d6cc2 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -201,6 +201,8 @@ struct device_queue_manager_ops {
void *ctl_stack);
void (*set_perfcount)(struct device_queue_manager *dqm,
int enable);
+ int (*clean_process_queues_cpsch)(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
};
struct device_queue_manager_asic_ops {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
index 04c5e26f01ed..da61d939b35c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
@@ -396,6 +396,12 @@ int kfd_init_apertures(struct kfd_process *process)
continue;
}
+ /* acquire pairs with the release in kgd2kfd_device_init() */
+ if (!smp_load_acquire(&dev->kfd->init_complete)) {
+ id++;
+ continue;
+ }
+
pdd = kfd_create_process_device_data(dev, process);
if (!pdd) {
dev_err(dev->adev->dev,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
index 1688d8e595f2..9b48fe598597 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
@@ -359,6 +359,24 @@ static bool event_interrupt_isr_v9(struct kfd_node *dev,
!amdgpu_no_queue_eviction_on_vm_fault);
}
+static void gfx942_clean_fault(uint16_t pasid)
+{
+ struct kfd_process *p;
+ struct kfd_process_device *pdd = NULL;
+ struct device_queue_manager *dqm;
+
+ p = kfd_lookup_process_by_pasid(pasid, &pdd);
+
+ if (!pdd)
+ return;
+
+ /* To Clean the GFX on the faulting device */
+ dqm = pdd->dev->dqm;
+ dqm->ops.clean_process_queues_cpsch(dqm, &pdd->qpd);
+
+ kfd_unref_process(p);
+}
+
static void event_interrupt_wq_v9(struct kfd_node *dev,
const uint32_t *ih_ring_entry)
{
@@ -547,6 +565,11 @@ static void event_interrupt_wq_v9(struct kfd_node *dev,
return;
}
+ /* GPR cleaner shader for MI2XX */
+ if (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2))
+ gfx942_clean_fault(pasid);
+
+
info.vmid = vmid;
info.mc_id = client_id;
info.page_addr = ih_ring_entry[4] |
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 6b64b1692235..8b96e1fe741a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -24,6 +24,8 @@
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/migrate.h>
+#include "amdgpu.h"
+#include "amdgpu_sdma.h"
#include "amdgpu_sync.h"
#include "amdgpu_object.h"
#include "amdgpu_vm.h"
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
index e034da638c07..4f8a8a1a6186 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
@@ -204,7 +204,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index 350fcbbba4b2..bf015dc5b868 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -242,7 +242,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
index 7c387fa90076..6ea09b031caf 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
@@ -217,7 +217,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
@@ -380,6 +380,63 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
#endif
+static void restore_mqd(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp, const void *mqd_src,
+ const void *ctl_stack_src, const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_compute_mqd *m;
+
+ m = (struct v12_compute_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ /* Update MQD base address to the newly allocated location */
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_pq_doorbell_control &=
+ ~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
+ m->cp_hqd_pq_doorbell_control |=
+ qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
+static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp,
+ const void *mqd_src,
+ const void *ctl_stack_src,
+ const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_sdma_mqd *m;
+
+ m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ m->sdmax_rlcx_doorbell_offset =
+ qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
struct kfd_node *dev)
{
@@ -407,6 +464,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
mqd->mqd_size = sizeof(struct v12_compute_mqd);
mqd->get_wave_state = get_wave_state;
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd;
#endif
@@ -453,6 +511,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_sdma;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
index 92ec081842df..ef74d62c9d56 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
@@ -321,7 +321,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
@@ -335,6 +335,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
/* GC 10 removed WPP_CLAMP from PQ Control */
m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK |
2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT |
+ 3 << CP_HQD_PQ_CONTROL__SCOPE__SHIFT |
1 << CP_HQD_PQ_CONTROL__QUEUE_FULL_EN__SHIFT;
m->cp_hqd_pq_doorbell_control |=
1 << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_BIF_DROP__SHIFT;
@@ -667,6 +668,72 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
#endif
+static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp, const void *mqd_src,
+ const void *ctl_stack_src, const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_1_compute_mqd *m;
+
+ /*
+ * GFX12.1 is multi-XCC capable but this restore handles XCC0 only.
+ * Multi-XCC CRIU restore is currently unreachable because
+ * kfd_criu_restore_queue() validates against unscaled mqd_size.
+ */
+ if (NUM_XCC(mm->dev->xcc_mask) > 1)
+ pr_warn_once("GFX12.1 multi-XCC CRIU restore not fully supported\n");
+
+ m = (struct v12_1_compute_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
+ NUM_XCC(mm->dev->xcc_mask));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ /* Update MQD base address to the newly allocated location */
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_pq_doorbell_control &=
+ ~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
+ m->cp_hqd_pq_doorbell_control |=
+ qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
+static void restore_mqd_sdma_v12_1(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp,
+ const void *mqd_src,
+ const void *ctl_stack_src,
+ const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_sdma_mqd *m;
+
+ m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ m->sdmax_rlcx_doorbell_offset =
+ qp->doorbell_off << SDMA0_SDMA_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
struct kfd_node *dev)
{
@@ -694,6 +761,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
mqd->mqd_size = sizeof(struct v12_1_compute_mqd);
mqd->get_wave_state = get_wave_state_v12_1;
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_v12_1;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd;
#endif
@@ -740,6 +808,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_sdma_v12_1;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index b95720198e28..6e6bc1ec0b64 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -285,6 +285,10 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
1 << CP_HQD_IB_CONTROL__IB_EXE_DISABLE__SHIFT;
/*
+ * The lowest 6 bits of eop_control store the EOP ring size. If
+ * their value is X, the ring size is 2^(X + 1) dwords, or
+ * 2^(X + 3) bytes.
+ *
* HW does not clamp this field correctly. Maximum EOP queue size
* is constrained by per-SE EOP done signal count, which is 8-bit.
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
@@ -296,7 +300,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
*
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ?
- min(0xA, order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
+ min(0xA, order_base_2(q->eop_ring_buffer_size / 8)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
index 60b87a500698..029572548c14 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -208,6 +208,9 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT;
/*
+ * The lowest 6 bits of eop_control store the EOP ring size. If
+ * their value is X, the ring size is 2^(X + 1) dwords, or
+ * 2^(X + 3) bytes.
* HW does not clamp this field correctly. Maximum EOP queue size
* is constrained by per-SE EOP done signal count, which is 8-bit.
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
@@ -215,7 +218,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control |= q->eop_ring_buffer_size ? min(0xA,
- order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
+ order_base_2(q->eop_ring_buffer_size / 8)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index dd938788bdd9..226f52626e84 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -318,8 +318,10 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer)
* XCCs in the partition.
* For PM4 queues, there is no cooperative dispatch so wave_cnt stay as it is.
*/
+ amdgpu_gfx_off_ctrl(dev->adev, false);
dev->kfd2kgd->get_cu_occupancy(dev->adev, cu_occupancy,
&max_waves_per_cu, ffs(dev->xcc_mask) - 1);
+ amdgpu_gfx_off_ctrl(dev->adev, true);
for (i = 0; i < AMDGPU_MAX_QUEUES; i++) {
if (cu_occupancy[i].wave_cnt != 0 &&
diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile
index 0084a8d55254..96242bb2f97c 100644
--- a/drivers/gpu/drm/amd/display/Makefile
+++ b/drivers/gpu/drm/amd/display/Makefile
@@ -42,6 +42,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dwb
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hpo
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mmhubbub
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mpc
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/rmcm
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/opp
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/pg
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/soc_and_ip_translator
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 b6ef2e005450..b5fef1f0b86b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -274,7 +274,6 @@ static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops;
* before passing control to DC.
*
* @dc: Display Core control structure
- * @update_type: specify whether it is FULL/MEDIUM/FAST update
* @planes_count: planes count to update
* @stream: stream state
* @stream_update: stream update
@@ -283,7 +282,6 @@ static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops;
*/
STATIC_IFN_KUNIT INLINE_IFN_KUNIT
bool update_planes_and_stream_adapter(struct dc *dc,
- int update_type,
int planes_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -607,6 +605,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
init_data.flags.enable_mipi_converter_optimization = true;
+ /*
+ * Request HW cursor offload so DMUB programs the cursor; cursor
+ * updates then avoid the DMUB inbox0 HW lock during mclk switches.
+ * dc_dmub_srv_cursor_offload_init() self-gates on FW capability.
+ */
+ init_data.flags.enable_cursor_offload = true;
+
init_data.dcn_reg_offsets = adev->reg_offset[DCE_HWIP][0];
init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0];
init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0];
@@ -724,6 +729,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
dc_hardware_init(adev->dm.dc);
+ /* Enable cursor offload if the DMUB firmware supports it. */
+ dc_dmub_srv_cursor_offload_init(adev->dm.dc);
+
/* GOP/vBIOS may leave an OPTC enabled for a display present at power-on
* but no longer driven (e.g. an external DP unplugged at boot). Such a
* dangling pipe keeps DCN out of idle and blocks s0i3. Power it down
@@ -1463,7 +1471,7 @@ STATIC_IFN_KUNIT void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
if (acrtc && state->stream_status[i].plane_count != 0 &&
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
if (rc)
drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n",
enable ? "enable" : "disable");
@@ -1487,7 +1495,7 @@ STATIC_IFN_KUNIT void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
/* During gpu-reset we disable and then enable vblank irq, so
* don't use amdgpu_irq_get/put() to avoid refcount change.
*/
- if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
+ if (!amdgpu_dm_irq_set(adev, irq_source, enable))
drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
} else if (acrtc && state->stream_status[i].plane_count != 0) {
@@ -1796,7 +1804,6 @@ STATIC_IFN_KUNIT void dm_gpureset_commit_state(struct dc_state *dc_state,
}
update_planes_and_stream_adapter(dm->dc,
- UPDATE_TYPE_FULL,
dc_state->stream_status[k].plane_count,
dc_state->streams[k],
&bundle->stream_update,
@@ -3876,6 +3883,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bool flip_latched_during_prog = false;
bool dirty_rects_changed = false;
bool updated_planes_and_streams = false;
+ bool stream_update_needed = false;
struct {
struct dc_surface_update surface_updates[MAX_SURFACES];
struct dc_plane_info plane_infos[MAX_SURFACES];
@@ -3909,6 +3917,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bundle->stream_update.cursor_position =
&acrtc_state->stream->cursor_position;
+ stream_update_needed = true;
}
if (acrtc_state->active_planes == 0 &&
@@ -3924,6 +3933,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bool plane_needs_flip;
struct dc_plane_state *dc_plane;
struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
+ struct dm_plane_state *dm_old_plane_state = to_dm_plane_state(old_plane_state);
/* Cursor plane is handled after stream updates */
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
@@ -3931,8 +3941,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
if ((fb && crtc == pcrtc) ||
(old_plane_state->fb && old_plane_state->crtc == pcrtc)) {
cursor_update = true;
- if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0)
+ if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) {
amdgpu_dm_update_cursor(plane, old_plane_state, &bundle->stream_update);
+ stream_update_needed = true;
+ }
}
continue;
@@ -3958,11 +3970,22 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bundle->surface_updates[planes_count].cm = &dc_plane->cm;
}
- amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
- &bundle->scaling_infos[planes_count]);
+ if (amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
+ &bundle->scaling_infos[planes_count])) {
+ planes_count += 1;
+ continue;
+ }
+
+ /* Cache the newly computed scaling_info in the plane state */
+ *dm_new_plane_state->scaling_info =
+ bundle->scaling_infos[planes_count];
- bundle->surface_updates[planes_count].scaling_info =
- &bundle->scaling_infos[planes_count];
+ /* Only send a scaling_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->scaling_info,
+ dm_new_plane_state->scaling_info,
+ sizeof(struct dc_scaling_info)))
+ bundle->surface_updates[planes_count].scaling_info =
+ &bundle->scaling_infos[planes_count];
plane_needs_flip = old_plane_state->fb && new_plane_state->fb;
@@ -3985,8 +4008,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
- bundle->surface_updates[planes_count].plane_info =
- &bundle->plane_infos[planes_count];
+ /* Cache the newly computed plane_info in the plane state */
+ *dm_new_plane_state->plane_info =
+ bundle->plane_infos[planes_count];
+
+ /* Only send a plane_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->plane_info,
+ dm_new_plane_state->plane_info,
+ sizeof(struct dc_plane_info)))
+ bundle->surface_updates[planes_count].plane_info =
+ &bundle->plane_infos[planes_count];
if (acrtc_state->stream->link->psr_settings.psr_feature_enabled ||
acrtc_state->stream->link->replay_settings.replay_feature_enabled) {
@@ -4041,7 +4072,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
timestamp_ns = ktime_get_ns();
bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
- bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count];
+ /* Cache the newly computed flip_addr in the plane state */
+ *dm_new_plane_state->flip_addr =
+ bundle->flip_addrs[planes_count];
+
+ /* Only send a flip_addr update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->flip_addr,
+ dm_new_plane_state->flip_addr,
+ sizeof(struct dc_flip_addrs)))
+ bundle->surface_updates[planes_count].flip_addr =
+ &bundle->flip_addrs[planes_count];
bundle->surface_updates[planes_count].surface = dc_plane;
if (!bundle->surface_updates[planes_count].surface) {
@@ -4113,6 +4153,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
&acrtc_state->stream->vrr_infopacket;
bundle->stream_update.vsp_infopacket =
&acrtc_state->stream->vsp_infopacket;
+ stream_update_needed = true;
}
}
}
@@ -4147,6 +4188,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
if (new_pcrtc_state->mode_changed) {
bundle->stream_update.src = acrtc_state->stream->src;
bundle->stream_update.dst = acrtc_state->stream->dst;
+ stream_update_needed = true;
}
if (new_pcrtc_state->color_mgmt_changed) {
@@ -4164,11 +4206,14 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
(struct dc_3dlut *) acrtc_state->stream->lut3d_func;
bundle->stream_update.func_shaper =
(struct dc_transfer_func *) acrtc_state->stream->func_shaper;
+ stream_update_needed = true;
}
acrtc_state->stream->abm_level = acrtc_state->abm_level;
- if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
+ if (acrtc_state->abm_level != dm_old_crtc_state->abm_level) {
bundle->stream_update.abm_level = &acrtc_state->abm_level;
+ stream_update_needed = true;
+ }
/*
* If FreeSync state on the stream has changed then we need to
@@ -4184,10 +4229,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
mutex_lock(&dm->dc_lock);
update_planes_and_stream_adapter(dm->dc,
- acrtc_state->update_type,
planes_count,
acrtc_state->stream,
- &bundle->stream_update,
+ stream_update_needed ? &bundle->stream_update : NULL,
bundle->surface_updates);
updated_planes_and_streams = true;
@@ -4571,6 +4615,13 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
(!new_crtc_state->active ||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
manage_dm_interrupts(adev, acrtc, NULL);
+ /*
+ * ISM hysteresis lives on system_dfl_wq, not the
+ * vblank workqueue. Wait it out so a timer armed while
+ * the stream existed cannot allow idle after the
+ * stream is released.
+ */
+ amdgpu_dm_ism_flush(&acrtc->ism);
dc_stream_release(dm_old_crtc_state->stream);
}
}
@@ -5446,7 +5497,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
struct drm_crtc_state *old_crtc_state,
struct drm_crtc_state *new_crtc_state,
bool enable,
- bool *lock_and_validation_needed)
+ bool *needs_dc_state_realloc)
{
struct dm_atomic_state *dm_state = NULL;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
@@ -5619,7 +5670,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
} else {/* Add stream for any updated/enabled CRTC */
/*
@@ -5657,7 +5708,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
goto fail;
}
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
}
}
@@ -5889,7 +5940,7 @@ dm_update_plane_state(struct dc *dc,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state,
bool enable,
- bool *lock_and_validation_needed,
+ bool *needs_dc_state_realloc,
bool *is_top_most_overlay)
{
@@ -5960,7 +6011,7 @@ dm_update_plane_state(struct dc *dc,
dm_new_plane_state->dc_state = NULL;
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
} else { /* Add new planes */
struct dc_plane_state *dc_new_plane_state;
@@ -6051,7 +6102,7 @@ dm_update_plane_state(struct dc *dc,
*/
dm_new_plane_state->dc_state->update_bits.full_update = 1;
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
}
out:
@@ -6208,7 +6259,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_plane_state *old_plane_state, *new_plane_state, *new_cursor_state;
enum dc_status status;
int ret, i;
- bool lock_and_validation_needed = false;
+ bool needs_dc_state_realloc = false;
bool is_top_most_overlay = true;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
struct drm_dp_mst_topology_mgr *mgr;
@@ -6382,7 +6433,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
false,
- &lock_and_validation_needed,
+ &needs_dc_state_realloc,
&is_top_most_overlay);
if (ret) {
drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
@@ -6396,7 +6447,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_crtc_state,
new_crtc_state,
false,
- &lock_and_validation_needed);
+ &needs_dc_state_realloc);
if (ret) {
drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
goto fail;
@@ -6409,7 +6460,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_crtc_state,
new_crtc_state,
true,
- &lock_and_validation_needed);
+ &needs_dc_state_realloc);
if (ret) {
drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
goto fail;
@@ -6422,7 +6473,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
true,
- &lock_and_validation_needed,
+ &needs_dc_state_realloc,
&is_top_most_overlay);
if (ret) {
drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
@@ -6537,7 +6588,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
continue;
- lock_and_validation_needed = true;
+ needs_dc_state_realloc = true;
}
/* set the slot info for each mst_state based on the link encoding format */
@@ -6573,7 +6624,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
*
* TODO: Remove this stall and drop DM state private objects.
*/
- if (lock_and_validation_needed) {
+ if (needs_dc_state_realloc) {
ret = dm_atomic_get_state(state, &dm_state);
if (ret) {
drm_dbg_atomic(dev, "dm_atomic_get_state() failed: %pe\n", ERR_PTR(ret));
@@ -6674,7 +6725,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
* the FB pitch, the DCC state, rotation, mem_type, etc.
*/
if (new_crtc_state->async_flip &&
- (lock_and_validation_needed ||
+ (needs_dc_state_realloc ||
amdgpu_dm_crtc_mem_type_changed(dev, state, new_crtc_state))) {
drm_dbg_atomic(crtc->dev,
"[CRTC:%d:%s] async flips are only supported for fast updates\n",
@@ -6683,7 +6734,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
goto fail;
}
- dm_new_crtc_state->update_type = lock_and_validation_needed ?
+ dm_new_crtc_state->update_type = needs_dc_state_realloc ?
UPDATE_TYPE_FULL : UPDATE_TYPE_FAST;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 52efebb2886d..1d256dce0e4b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -333,6 +333,7 @@ struct hpd_rx_irq_offload_work {
* @backlight_link: Link on which to control backlight
* @backlight_caps: Capabilities of the backlight device
* @freesync_module: Module handling freesync calculations
+ * @power_module: Module handling power calculations
* @hdcp_workqueue: AMDGPU content protection queue
* @fw_dmcu: Reference to DMCU firmware
* @dmcu_fw_version: Version of the DMCU firmware
@@ -556,6 +557,18 @@ struct amdgpu_display_manager {
vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
/**
+ * @irq_reg_lock:
+ *
+ * Serializes the read-modify-writes of the HW interrupt control
+ * registers. Several interrupt sources share one register - e.g. the
+ * enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK
+ * live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must
+ * not race with acking another. Held only across amdgpu_dm_irq_set()
+ * and amdgpu_dm_irq_ack().
+ */
+ spinlock_t irq_reg_lock;
+
+ /**
* @dmub_trace_params:
*
* DMUB trace event IRQ parameters, passed to registered handlers when
@@ -719,16 +732,26 @@ struct amdgpu_display_manager {
char reply_data[0x40]; // Cannot include dmub_cmd here
} fused_io[8];
/**
- * @hdmi_frl_status_polling_work:
+ * @hdmi_frl_status_polling_wq:
*
* workqueue for 200ms frl status polling
*/
struct workqueue_struct *hdmi_frl_status_polling_wq;
+ /**
+ * @hdmi_frl_status_polling_work:
+ *
+ * Delayed work for 200ms HDMI FRL status polling.
+ */
struct delayed_work hdmi_frl_status_polling_work;
+ /**
+ * @hdmi_frl_status_polling_delay_ms:
+ *
+ * Delay, in milliseconds, between HDMI FRL status polls.
+ */
unsigned int hdmi_frl_status_polling_delay_ms;
/**
- * @dm_boot_time_crc_info:
+ * @boot_time_crc_info:
*
* Buffer info for the boot time crc.
*/
@@ -937,6 +960,10 @@ enum amdgpu_transfer_function {
AMDGPU_TRANSFER_FUNCTION_COUNT
};
+struct dc_flip_addrs;
+struct dc_scaling_info;
+struct dc_plane_info;
+
struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
@@ -1006,6 +1033,16 @@ struct dm_plane_state {
* applying blend LUT.
*/
enum amdgpu_transfer_function blend_tf;
+
+ /* Cached per-plane surface descriptors kept in the DRM plane state.
+ * The DRM atomic old/new state swap lets us compare the previous
+ * commit's values (old) against the newly computed ones to detect a
+ * real plane change (vs an address-only flip) so DC only gets a
+ * scaling_info/plane_info surface update when it actually changed.
+ */
+ struct dc_flip_addrs *flip_addr;
+ struct dc_scaling_info *scaling_info;
+ struct dc_plane_info *plane_info;
};
enum amdgpu_dm_cursor_mode {
@@ -1237,7 +1274,6 @@ void s3_handle_mst(struct drm_device *dev, bool suspend);
void dm_gpureset_commit_state(struct dc_state *dc_state, struct amdgpu_display_manager *dm);
int dm_plane_layer_index_cmp(const void *a, const void *b);
bool update_planes_and_stream_adapter(struct dc *dc,
- int update_type,
int planes_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index c1b5394617a3..31e9f029a707 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1267,6 +1267,12 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
dc_link_get_link_cap(aconnector->dc_link));
+ if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled) {
+ dsc_options.max_target_bpp_limit_override_x16 = 8 * 16;
+ dsc_options.force_dsc_when_not_needed = true;
+ }
+
/* Set DSC policy according to dsc_clock_en */
dc_dsc_policy_set_enable_dsc_when_not_needed(
aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
@@ -2326,7 +2332,9 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
* (drm_mode_is_420_also() clear), as required for HDMI compliance
* testing; dc_validate_stream() still rejects anything the link
* genuinely cannot carry. The YCbCr422/YCbCr444 forces stay gated on
- * the sink's advertised caps.
+ * the sink's advertised caps. An RGB force pins to RGB alone and is
+ * always honoured, since RGB is the mandatory baseline every sink
+ * (DP or HDMI) supports.
*/
want_420 = (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) ||
(drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
@@ -2346,7 +2354,8 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
is_dp_or_hdmi) {
encoding_mask = BIT(PIXEL_ENCODING_YCBCR444);
- } else if (drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444) {
+ } else if ((aconnector->force_yuv_pixel_format == PIXEL_ENCODING_RGB) ||
+ (drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444)) {
encoding_mask = BIT(PIXEL_ENCODING_RGB);
} else {
encoding_mask = BIT(PIXEL_ENCODING_RGB);
@@ -3322,6 +3331,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
}
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_init_helper);
STATIC_IFN_KUNIT int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
@@ -3426,6 +3436,7 @@ int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_initialize_hdmi_connector);
/*
* Note: this function assumes that dc_link_detect() was called for the
@@ -3503,8 +3514,9 @@ out_free:
}
return res;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_init);
-static int dm_force_atomic_commit(struct drm_connector *connector)
+STATIC_IFN_KUNIT int dm_force_atomic_commit(struct drm_connector *connector)
{
int ret = 0;
struct drm_device *ddev = connector->dev;
@@ -3564,6 +3576,7 @@ out:
return ret;
}
+EXPORT_IF_KUNIT(dm_force_atomic_commit);
/*
* This function handles all cases when set mode does not come upon hotplug.
@@ -3892,3 +3905,4 @@ update:
drm_connector_set_vrr_capable_property(connector,
freesync_capable);
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_freesync_caps);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index fb3f3d8a5283..79698deacf61 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -226,5 +226,6 @@ void amdgpu_dm_update_cacp_caps(struct amdgpu_dm_connector *aconnector);
struct drm_atomic_commit;
int amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
struct drm_atomic_commit *state);
+int dm_force_atomic_commit(struct drm_connector *connector);
#endif
#endif /* __AMDGPU_DM_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 686da9c477db..5036ac1c4fd5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -31,6 +31,7 @@
#include "amdgpu_dm_psr.h"
#include "amdgpu_dm_replay.h"
#include "amdgpu_dm_crtc.h"
+#include "amdgpu_dm_irq.h"
#include "amdgpu_dm_plane.h"
#include "amdgpu_dm_trace.h"
#include "amdgpu_dm_debugfs.h"
@@ -91,7 +92,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
acrtc->crtc_id, enable ? "en" : "dis", rc);
@@ -480,9 +481,9 @@ EXPORT_IF_KUNIT(amdgpu_dm_crtc_duplicate_state);
STATIC_IFN_KUNIT void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
{
/*
- * amdgpu_dm_ism_fini() is intentionally called in amdgpu_dm_fini().
- * It must be called before dc_destroy() in amdgpu_dm_fini()
- * to avoid ISM accessing an invalid dc handle once dc is released.
+ * ISM workers are intentionally quiesced by amdgpu_dm_ism_disable()
+ * in amdgpu_dm_fini(). That must happen before dc_destroy() so ISM
+ * cannot access an invalid dc handle once dc is released.
*/
drm_crtc_cleanup(crtc);
@@ -841,7 +842,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
return 0;
error_ism_fini:
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
drm_crtc_cleanup(&acrtc->base);
fail:
kfree(acrtc);
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 5d4f578851ae..3217aa82bea2 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
@@ -1470,12 +1470,13 @@ EXPORT_IF_KUNIT(dm_helpers_free_gpu_mem);
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
{
+ struct amdgpu_device *adev = ctx->driver_context;
enum dc_irq_source irq_source;
bool ret;
irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
- ret = dc_interrupt_set(ctx->dc, irq_source, enable);
+ ret = amdgpu_dm_irq_set(adev, irq_source, enable);
DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
enable ? "en" : "dis", ret);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index f997a50c1293..c3ed63843202 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -396,6 +396,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
DRM_DEBUG_KMS("DM_IRQ\n");
spin_lock_init(&adev->dm.irq_handler_list_table_lock);
+ spin_lock_init(&adev->dm.irq_reg_lock);
adev->dm.irq_wq = alloc_workqueue("amdgpu_dm_irq",
WQ_UNBOUND | WQ_HIGHPRI, 0);
@@ -530,7 +531,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
*/
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
- dc_interrupt_set(adev->dm.dc, src, false);
+ amdgpu_dm_irq_set(adev, src, false);
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -568,7 +569,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
- dc_interrupt_set(adev->dm.dc, src, true);
+ amdgpu_dm_irq_set(adev, src, true);
}
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -594,7 +595,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
- dc_interrupt_set(adev->dm.dc, src, true);
+ amdgpu_dm_irq_set(adev, src, true);
}
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -693,6 +694,23 @@ STATIC_IFN_KUNIT void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
}
EXPORT_IF_KUNIT(amdgpu_dm_irq_immediate_work);
+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
+ bool enable)
+{
+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
+
+ return dc_interrupt_set(adev->dm.dc, src, enable);
+}
+EXPORT_IF_KUNIT(amdgpu_dm_irq_set);
+
+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src)
+{
+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
+
+ dc_interrupt_ack(adev->dm.dc, src);
+}
+EXPORT_IF_KUNIT(amdgpu_dm_irq_ack);
+
/**
* amdgpu_dm_irq_handler - Generic DM IRQ handler
* @adev: amdgpu base driver device containing the DM device
@@ -718,7 +736,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
return 0;
}
- dc_interrupt_ack(adev->dm.dc, src);
+ amdgpu_dm_irq_ack(adev, src);
/* Call high irq work immediately */
amdgpu_dm_irq_immediate_work(adev, src);
@@ -758,7 +776,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev,
enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type);
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, src, st);
+ amdgpu_dm_irq_set(adev, src, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_hpd_irq_state);
@@ -793,7 +811,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
dc_allow_idle_optimizations(dc, false);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
@@ -850,7 +868,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *a
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_outbox_irq_state);
@@ -878,7 +896,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_trace_irq_state(struct amdgpu_device *ad
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0;
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_trace_irq_state);
@@ -945,9 +963,7 @@ EXPORT_IF_KUNIT(amdgpu_dm_set_irq_funcs);
void amdgpu_dm_outbox_init(struct amdgpu_device *adev)
{
- dc_interrupt_set(adev->dm.dc,
- DC_IRQ_SOURCE_DMCUB_OUTBOX,
- true);
+ amdgpu_dm_irq_set(adev, DC_IRQ_SOURCE_DMCUB_OUTBOX, true);
}
EXPORT_IF_KUNIT(amdgpu_dm_outbox_init);
@@ -970,7 +986,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
/* First, clear all hpd and hpdrx interrupts */
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
- if (!dc_interrupt_set(adev->dm.dc, i, false))
+ if (!amdgpu_dm_irq_set(adev, i, false))
drm_err(dev, "Failed to clear hpd(rx) source=%d on init\n",
i);
}
@@ -999,7 +1015,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
* of dm. Note that only hpd interrupt types are registered with
* base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
* hpd_rx isn't available. DM currently controls hpd_rx
- * explicitly with dc_interrupt_set()
+ * explicitly with amdgpu_dm_irq_set()
*/
if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
@@ -1008,23 +1024,21 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
* and what bios reports as the # of connectors with hpd
* sources. Since the # of hpd source types registered
* with base driver == mode_info.num_hpd, we have to
- * fallback to dc_interrupt_set for the remaining types.
+ * fallback to amdgpu_dm_irq_set for the remaining types.
*/
if (irq_type < adev->mode_info.num_hpd) {
if (amdgpu_irq_get(adev, &adev->hpd_irq, irq_type))
drm_err(dev, "DM_IRQ: Failed get HPD for source=%d)!\n",
dc_link->irq_source_hpd);
} else {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd,
- true);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
+ true);
}
}
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd_rx,
- true);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
+ true);
}
}
drm_connector_list_iter_end(&iter);
@@ -1069,16 +1083,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
drm_err(dev, "DM_IRQ: Failed put HPD for source=%d!\n",
dc_link->irq_source_hpd);
} else {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd,
- false);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
+ false);
}
}
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd_rx,
- false);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
+ false);
}
}
drm_connector_list_iter_end(&iter);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
index 4c200a9614a7..bc16ecc67329 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
@@ -89,6 +89,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
enum dc_irq_source irq_source,
void *ih_index);
+/**
+ * amdgpu_dm_irq_set - enable or disable a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to toggle
+ * @enable: true to enable the source, false to disable it
+ *
+ * DM-wide replacement for dc_interrupt_set(). As locking is DM's
+ * responsibility, this is a thin wrapper serializes the underlying
+ * read-modify-write against the other interrupt sources sharing HW control
+ * registers with @src, so DM must never call dc_interrupt_set() directly.
+ *
+ * Returns: true if the source was toggled.
+ */
+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
+ bool enable);
+
+/**
+ * amdgpu_dm_irq_ack - acknowledge a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to acknowledge
+ *
+ * DM-wide replacement for dc_interrupt_ack(), serialized the same way as
+ * amdgpu_dm_irq_set().
+ */
+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src);
+
void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);
void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
index 4e57572e12b6..127eaba4de60 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
@@ -647,9 +647,26 @@ void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
EXPORT_IF_KUNIT(amdgpu_dm_ism_init);
-void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism)
+/**
+ * amdgpu_dm_ism_flush - Cancel any pending, or wait out in-flight ISM work
+ *
+ * @ism: The CRTC's idle state manager
+ *
+ * Cancels the hysteresis and SSO timers and waits for a running worker to
+ * finish. Callers that are about to drop the CRTC's stream use this so that a
+ * timer armed while the stream was still around cannot allow idle afterwards.
+ *
+ * Must not be called with dc_lock held: the workers take dc_lock themselves,
+ * so waiting for them under it would deadlock.
+ */
+void amdgpu_dm_ism_flush(struct amdgpu_dm_ism *ism)
{
+ struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
+ struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
+
+ lockdep_assert_not_held(&adev->dm.dc_lock);
+
cancel_delayed_work_sync(&ism->sso_delayed_work);
cancel_delayed_work_sync(&ism->delayed_work);
}
-EXPORT_IF_KUNIT(amdgpu_dm_ism_fini);
+EXPORT_IF_KUNIT(amdgpu_dm_ism_flush);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
index afce16f7085a..893e062bb281 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
@@ -142,7 +142,7 @@ struct amdgpu_dm_ism {
void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
struct amdgpu_dm_ism_config *config);
-void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism);
+void amdgpu_dm_ism_flush(struct amdgpu_dm_ism *ism);
void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event);
void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm);
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 bce605fd6cdf..a5b15bef8aa0 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
@@ -278,8 +278,8 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
}
EXPORT_IF_KUNIT(needs_dsc_aux_workaround);
-#if defined(CONFIG_DRM_AMD_DC_FP)
-static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+STATIC_IFN_KUNIT bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
{
u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F
@@ -293,8 +293,9 @@ static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_m
return false;
}
+EXPORT_IF_KUNIT(is_synaptics_cascaded_panamera);
-static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
{
struct dc_sink *dc_sink = aconnector->dc_sink;
struct drm_dp_mst_port *port = aconnector->mst_output_port;
@@ -338,6 +339,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
return true;
}
+EXPORT_IF_KUNIT(validate_dsc_caps_on_connector);
#endif
STATIC_IFN_KUNIT bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector)
@@ -504,8 +506,8 @@ STATIC_IFN_KUNIT int dm_dp_mst_get_modes(struct drm_connector *connector)
amdgpu_dm_update_freesync_caps(
connector, aconnector->drm_edid, true);
-#if defined(CONFIG_DRM_AMD_DC_FP)
- if (!validate_dsc_caps_on_connector(aconnector))
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+ if (IS_ENABLED(CONFIG_DRM_AMD_DC_FP) && !validate_dsc_caps_on_connector(aconnector))
memset(&aconnector->dc_sink->dsc_caps,
0, sizeof(aconnector->dc_sink->dsc_caps));
#endif
@@ -660,7 +662,7 @@ dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev)
}
EXPORT_IF_KUNIT(dm_dp_create_fake_mst_encoders);
-static struct drm_connector *
+STATIC_IFN_KUNIT struct drm_connector *
dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port,
const char *pathprop)
@@ -742,6 +744,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
return connector;
}
+EXPORT_IF_KUNIT(dm_dp_add_mst_connector);
/*
* Select the ESI[1] mask used to filter the MST sideband ready bits for a
@@ -937,7 +940,7 @@ struct dsc_mst_fairness_params {
struct amdgpu_dm_connector *aconnector;
};
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link)
{
u8 link_coding_cap;
@@ -1228,8 +1231,8 @@ static int try_disable_dsc(struct drm_atomic_commit *state,
return 0;
}
-static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
- uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
+STATIC_IFN_KUNIT bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
+ uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
{
unsigned int max_conv_bw_in_kbps = 0;
unsigned int max_sink_bw_in_kbps = 0;
@@ -1255,6 +1258,7 @@ static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
return *bw_in_kbps > 0; // Frl endpoint is detected
}
+EXPORT_IF_KUNIT(get_conv_frl_bw);
static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream,
@@ -1299,7 +1303,7 @@ static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
}
}
-static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
+STATIC_IFN_KUNIT void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
{
int i;
@@ -1307,6 +1311,7 @@ static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
DRM_DEBUG_DRIVER("MST_DSC DSC params: stream #%d --- dsc_enabled = %d, bpp_x16 = %d, pbn = %d\n",
i, vars[i + k].dsc_enabled, vars[i + k].bpp_x16, vars[i + k].pbn);
}
+EXPORT_IF_KUNIT(log_dsc_params);
static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
struct dc_state *dc_state,
@@ -1370,6 +1375,10 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
params[count].num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
+ if (params[count].compression_possible &&
+ dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ dc_link->dpia_bw_alloc_config.bw_alloc_enabled)
+ params[count].clock_force_enable = DSC_CLK_FORCE_ENABLE;
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps);
if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported &&
@@ -1381,7 +1390,10 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
stream->sink->ctx->dc->res_pool->dscs[0],
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,
dsc_policy.min_target_bpp * 16,
- dsc_policy.max_target_bpp * 16,
+ (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ dc_link->dpia_bw_alloc_config.bw_alloc_enabled) ?
+ dsc_policy.min_target_bpp * 16 :
+ dsc_policy.max_target_bpp * 16,
&stream->sink->dsc_caps.dsc_dec_caps,
&stream->timing,
dc_link_get_highest_encoding_format(dc_link),
@@ -1480,7 +1492,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
return 0;
}
-static bool is_dsc_need_re_compute(
+STATIC_IFN_KUNIT bool is_dsc_need_re_compute(
struct drm_atomic_commit *state,
struct dc_state *dc_state,
struct dc_link *dc_link)
@@ -1611,6 +1623,7 @@ out:
return is_dsc_need_re_compute;
}
+EXPORT_IF_KUNIT(is_dsc_need_re_compute);
int compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
struct dc_state *dc_state,
@@ -1681,10 +1694,11 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
return ret;
}
+EXPORT_IF_KUNIT(compute_mst_dsc_configs_for_state);
-static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
- struct dc_state *dc_state,
- struct dsc_mst_fairness_vars *vars)
+STATIC_IFN_KUNIT int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars)
{
int i, j;
struct dc_stream_state *stream;
@@ -1734,9 +1748,10 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state
return ret;
}
+EXPORT_IF_KUNIT(pre_compute_mst_dsc_configs_for_state);
-static int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
- struct dc_stream_state *stream)
+STATIC_IFN_KUNIT int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
+ struct dc_stream_state *stream)
{
int i;
struct drm_crtc *crtc;
@@ -1750,6 +1765,7 @@ static int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
}
return -1;
}
+EXPORT_IF_KUNIT(find_crtc_index_in_state_by_stream);
static bool is_link_to_dschub(struct dc_link *dc_link)
{
@@ -1766,7 +1782,7 @@ static bool is_link_to_dschub(struct dc_link *dc_link)
return true;
}
-static bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
+STATIC_IFN_KUNIT bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
{
int i;
struct drm_crtc *crtc;
@@ -1786,6 +1802,7 @@ static bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
}
return ret;
}
+EXPORT_IF_KUNIT(is_dsc_precompute_needed);
int pre_validate_dsc(struct drm_atomic_commit *state,
struct dm_atomic_state **dm_state_ptr,
@@ -1897,6 +1914,7 @@ clean_exit:
return ret;
}
+EXPORT_IF_KUNIT(pre_validate_dsc);
static uint32_t kbps_from_pbn(unsigned int pbn)
{
@@ -1928,8 +1946,8 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream,
}
#endif
-#if defined(CONFIG_DRM_AMD_DC_FP)
-static bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+STATIC_IFN_KUNIT bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw)
{
uint32_t total_data_bw_efficiency_x10000 = 0;
uint32_t link_rate_per_lane_kbps = 0;
@@ -1984,13 +2002,14 @@ static bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_lin
*cur_link_bw = link_rate_per_lane_kbps * lane_count.bits.LANE_COUNT_SET / 10000 * total_data_bw_efficiency_x10000;
return true;
}
+EXPORT_IF_KUNIT(dp_get_link_current_set_bw);
#endif
enum dc_status dm_dp_mst_is_port_support_mode(
struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream)
{
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
int branch_max_throughput_mps = 0;
struct dc_link_settings cur_link_settings;
uint32_t end_to_end_bw_in_kbps = 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 50dca0ef98fe..4436d256a2ae 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -65,6 +65,8 @@ struct dc_state;
struct dc_stream_state;
struct dm_atomic_state;
struct drm_atomic_commit;
+struct drm_dp_aux;
+struct drm_dp_mst_port;
struct drm_dp_mst_topology_mgr;
uint32_t dm_mst_get_pbn_divider(struct dc_link *link);
@@ -103,6 +105,20 @@ enum dc_status dm_dp_mst_is_port_support_mode(
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
+bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port);
+bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
+bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
+ uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps);
+void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k);
+int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
+ struct dc_stream_state *stream);
+bool is_dsc_precompute_needed(struct drm_atomic_commit *state);
+bool is_dsc_need_re_compute(struct drm_atomic_commit *state, struct dc_state *dc_state,
+ struct dc_link *dc_link);
+int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars);
+bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
ssize_t dm_dp_aux_transfer_result(ssize_t result,
@@ -119,6 +135,9 @@ int dm_dp_mst_atomic_check(struct drm_connector *connector,
int dm_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force);
int dm_dp_mst_get_modes(struct drm_connector *connector);
+struct drm_connector *dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_port *port,
+ const char *pathprop);
int amdgpu_dm_mst_connector_late_register(struct drm_connector *connector);
void amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector);
void dm_dp_mst_connector_destroy(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index d357afcb0e93..2f88b9d65b82 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -34,6 +34,7 @@
#include <drm/drm_fourcc.h>
#include "amdgpu.h"
+#include "dc.h"
#include "dal_asic_id.h"
#include "amdgpu_display.h"
#include "amdgpu_dm_trace.h"
@@ -1807,6 +1808,21 @@ STATIC_IFN_KUNIT struct drm_plane_state *amdgpu_dm_plane_drm_plane_create_state(
if (!amdgpu_state)
return ERR_PTR(-ENOMEM);
+ amdgpu_state->flip_addr = kzalloc_obj(*amdgpu_state->flip_addr);
+ amdgpu_state->scaling_info = kzalloc_obj(*amdgpu_state->scaling_info);
+ amdgpu_state->plane_info = kzalloc_obj(*amdgpu_state->plane_info);
+ if (!amdgpu_state->flip_addr || !amdgpu_state->scaling_info ||
+ !amdgpu_state->plane_info) {
+ kfree(amdgpu_state->flip_addr);
+ kfree(amdgpu_state->scaling_info);
+ kfree(amdgpu_state->plane_info);
+ kfree(amdgpu_state);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (plane->state)
+ plane->funcs->atomic_destroy_state(plane, plane->state);
+
__drm_atomic_helper_plane_state_init(&amdgpu_state->base, plane);
amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
@@ -1827,6 +1843,21 @@ amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
if (!dm_plane_state)
return NULL;
+ dm_plane_state->flip_addr = kmemdup(old_dm_plane_state->flip_addr,
+ sizeof(*old_dm_plane_state->flip_addr), GFP_KERNEL);
+ dm_plane_state->scaling_info = kmemdup(old_dm_plane_state->scaling_info,
+ sizeof(*old_dm_plane_state->scaling_info), GFP_KERNEL);
+ dm_plane_state->plane_info = kmemdup(old_dm_plane_state->plane_info,
+ sizeof(*old_dm_plane_state->plane_info), GFP_KERNEL);
+ if (!dm_plane_state->flip_addr || !dm_plane_state->scaling_info ||
+ !dm_plane_state->plane_info) {
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+ kfree(dm_plane_state);
+ return NULL;
+ }
+
__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
if (old_dm_plane_state->dc_state) {
@@ -1946,6 +1977,10 @@ STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *
if (dm_plane_state->blend_lut)
drm_property_blob_put(dm_plane_state->blend_lut);
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+
if (dm_plane_state->dc_state)
dc_plane_state_release(dm_plane_state->dc_state);
@@ -2327,6 +2362,7 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_plane_init);
bool amdgpu_dm_plane_is_video_format(uint32_t format)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 8107be27d324..8117aaf41f22 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -16,6 +16,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_property.h>
#include <linux/hdmi.h>
#include <linux/i2c.h>
@@ -27,6 +28,8 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_connector.h"
#include "amdgpu_dm_backlight.h"
+#include "amdgpu_dm_hdcp.h"
+#include "amdgpu_dm_psr.h"
#include "include/grph_object_id.h"
#include "amdgpu_dm_kunit_test_helpers.h"
#include "inc/link_service.h"
@@ -4181,6 +4184,217 @@ static void dm_test_create_stream_existing_sink(struct kunit *test)
dc_sink_release(sink);
}
+/* Append a copy of the context mode to the connector's mode list. */
+static void dm_test_stream_add_mode(struct kunit *test, struct dm_test_stream_ctx *ctx,
+ u32 type)
+{
+ struct drm_display_mode *mode = drm_mode_create(ctx->drm);
+
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+ drm_mode_copy(mode, ctx->mode);
+ mode->type = type;
+ list_add_tail(&mode->head, &ctx->aconnector->base.modes);
+}
+
+/* Give the context mode a full set of CRTC timings. */
+static void dm_test_stream_set_timings(struct dm_test_stream_ctx *ctx)
+{
+ ctx->mode->hsync_start = 2008;
+ ctx->mode->hsync_end = 2052;
+ ctx->mode->htotal = 2200;
+ ctx->mode->vsync_start = 1084;
+ ctx->mode->vsync_end = 1089;
+ ctx->mode->vtotal = 1125;
+}
+
+/* Create a real dc_sink of @signal owned by the caller. */
+static struct dc_sink *dm_test_stream_add_sink(struct kunit *test,
+ struct dm_test_stream_ctx *ctx,
+ enum signal_type signal)
+{
+ struct dc_sink_init_data sink_init = { 0 };
+ struct dc_sink *sink;
+
+ sink_init.link = ctx->link;
+ sink_init.sink_signal = signal;
+ sink = dc_sink_create(&sink_init);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ sink->sink_signal = signal;
+ ctx->aconnector->dc_sink = sink;
+
+ return sink;
+}
+
+/**
+ * dm_test_create_stream_preferred_mode - Test the preferred mode drives the timing
+ * @test: The KUnit test context
+ *
+ * A preferred mode in the connector's mode list is used to recompute the CRTC
+ * timings of the requested mode before the stream properties are filled in.
+ */
+static void dm_test_create_stream_preferred_mode(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ dm_test_stream_set_timings(ctx);
+ dm_test_stream_add_mode(test, ctx, DRM_MODE_TYPE_PREFERRED);
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1920);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.v_addressable, 1080);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_total, 2200);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.v_total, 1125);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_scaled_keeps_refresh - Test scaling reuses the old timing
+ * @test: The KUnit test context
+ *
+ * With scaling enabled and an unchanged refresh rate the stream properties are
+ * filled from the old stream so the VIC and sync polarities are preserved.
+ */
+static void dm_test_create_stream_scaled_keeps_refresh(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ dm_test_stream_set_timings(ctx);
+ dm_test_stream_add_mode(test, ctx, DRM_MODE_TYPE_PREFERRED);
+ ctx->dm_state->scaling = RMX_FULL;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1920);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_timing_override - Test the automated test timing override
+ * @test: The KUnit test context
+ *
+ * A connector carrying a requested timing from an automated test replaces the
+ * timing derived from the mode.
+ */
+static void dm_test_create_stream_timing_override(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_crtc_timing *timing;
+ struct dc_stream_state *stream;
+
+ timing = kunit_kzalloc(test, sizeof(*timing), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, timing);
+ timing->h_addressable = 1280;
+ timing->v_addressable = 720;
+ timing->display_color_depth = COLOR_DEPTH_101010;
+
+ ctx->aconnector->timing_changed = true;
+ ctx->aconnector->timing_requested = timing;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1280);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.display_color_depth,
+ (int)COLOR_DEPTH_101010);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_dp_vsc_colorimetry - Test the DP VSC SDP colorimetry decision
+ * @test: The KUnit test context
+ *
+ * A DisplayPort sink on a DPCD 1.4 link advertising VSC SDP colorimetry, and
+ * without the disable-colorimetry quirk, enables VSC SDP colorimetry and
+ * arms the self refresh entry delay.
+ */
+static void dm_test_create_stream_dp_vsc_colorimetry(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_DISPLAY_PORT);
+ ctx->link->dpcd_caps.dpcd_rev.raw = 0x14;
+ ctx->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED = 1;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_DISPLAY_PORT);
+ KUNIT_EXPECT_TRUE(test, stream->use_vsc_sdp_for_colorimetry);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->sr_skip_count, AMDGPU_DM_PSR_ENTRY_DELAY);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
+/**
+ * dm_test_create_stream_dp_colorimetry_quirk - Test the disable colorimetry quirk
+ * @test: The KUnit test context
+ */
+static void dm_test_create_stream_dp_colorimetry_quirk(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_DISPLAY_PORT);
+ sink->edid_caps.panel_patch.disable_colorimetry = true;
+ ctx->link->dpcd_caps.dpcd_rev.raw = 0x14;
+ ctx->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED = 1;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_FALSE(test, stream->use_vsc_sdp_for_colorimetry);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
+/**
+ * dm_test_create_stream_hdmi_vsif - Test the HDMI vendor specific infoframe
+ * @test: The KUnit test context
+ *
+ * An HDMI sink takes the HDMI Forum vendor specific infoframe path. A plain
+ * 2D, non-HDMI-VIC timing carries no payload, so the packet stays invalid.
+ */
+static void dm_test_create_stream_hdmi_vsif(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ ctx->link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_HDMI_TYPE_A);
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_HDMI_TYPE_A);
+ KUNIT_EXPECT_FALSE(test, stream->vsp_infopacket.valid);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
/* Tests for amdgpu_dm_connector_detect() */
/*
@@ -6134,331 +6348,6 @@ static void dm_test_restore_state_same_sink(struct kunit *test)
KUNIT_EXPECT_PTR_EQ(test, stream->sink, aconnector->dc_sink);
}
-/* Mock DMCU plumbing for parse_edid_cea_dmcu() tests. */
-static bool dm_test_dmcu_is_init(struct dmcu *dmcu)
-{
- return true;
-}
-
-static bool dm_test_dmcu_send_cea(struct dmcu *dmcu, int offset,
- int total_length, u8 *data, int length)
-{
- return true;
-}
-
-static bool dm_test_dmcu_recv_ack_ok(struct dmcu *dmcu, int *offset)
-{
- *offset = 0;
- return true;
-}
-
-static bool dm_test_dmcu_recv_ack_fail(struct dmcu *dmcu, int *offset)
-{
- return false;
-}
-
-static bool dm_test_dmcu_recv_vsdb_found(struct dmcu *dmcu, int *version,
- int *min_frame_rate, int *max_frame_rate)
-{
- *version = 2;
- *min_frame_rate = 24;
- *max_frame_rate = 60;
- return true;
-}
-
-static bool dm_test_dmcu_recv_vsdb_none(struct dmcu *dmcu, int *version,
- int *min_frame_rate, int *max_frame_rate)
-{
- return false;
-}
-
-static const struct dmcu_funcs dm_test_dmcu_funcs_vsdb = {
- .is_dmcu_initialized = dm_test_dmcu_is_init,
- .send_edid_cea = dm_test_dmcu_send_cea,
- .recv_edid_cea_ack = dm_test_dmcu_recv_ack_ok,
- .recv_amd_vsdb = dm_test_dmcu_recv_vsdb_found,
-};
-
-static const struct dmcu_funcs dm_test_dmcu_funcs_novsdb = {
- .is_dmcu_initialized = dm_test_dmcu_is_init,
- .send_edid_cea = dm_test_dmcu_send_cea,
- .recv_edid_cea_ack = dm_test_dmcu_recv_ack_ok,
- .recv_amd_vsdb = dm_test_dmcu_recv_vsdb_none,
-};
-
-static const struct dmcu_funcs dm_test_dmcu_funcs_ackfail = {
- .is_dmcu_initialized = dm_test_dmcu_is_init,
- .send_edid_cea = dm_test_dmcu_send_cea,
- .recv_edid_cea_ack = dm_test_dmcu_recv_ack_fail,
- .recv_amd_vsdb = dm_test_dmcu_recv_vsdb_none,
-};
-
-/*
- * Build a bare display manager carrying a dc with a resource pool whose DMCU
- * uses the supplied funcs table (or no DMCU at all when @funcs is NULL). The
- * DMCU CEA parser path only touches dm->dc->res_pool->dmcu, so no adev/ctx is
- * required.
- */
-static struct amdgpu_display_manager *
-dm_test_alloc_dm_dmcu(struct kunit *test, const struct dmcu_funcs *funcs)
-{
- struct amdgpu_display_manager *dm;
- struct resource_pool *pool;
- struct dmcu *dmcu = NULL;
- struct dc *dc;
-
- dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, dm);
- dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, dc);
- pool = kunit_kzalloc(test, sizeof(*pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, pool);
-
- if (funcs) {
- dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, dmcu);
- dmcu->funcs = funcs;
- }
-
- pool->dmcu = dmcu;
- dc->res_pool = pool;
- dm->dc = dc;
- return dm;
-}
-
-/*
- * Build a display manager backed by an amdgpu_device and a dc with a ctx (but
- * no DMUB), so the DMUB CEA send path can build a command, fail the execute,
- * and log via drm_err() safely.
- */
-static struct amdgpu_display_manager *dm_test_alloc_dm_adev(struct kunit *test)
-{
- struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
- struct dc *dc = dm_kunit_alloc_dc_with_ctx(test);
-
- KUNIT_ASSERT_NOT_NULL(test, adev);
- KUNIT_ASSERT_NOT_NULL(test, dc);
- adev->dm.adev = adev;
- adev->dm.dc = dc;
- return &adev->dm;
-}
-
-/**
- * dm_test_send_cea_length_too_long - Test an oversized chunk is rejected
- * @test: KUnit test context
- */
-static void dm_test_send_cea_length_too_long(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 data[16] = {0};
- bool ret;
-
- ret = dm_edid_parser_send_cea(dm, 0, 128, data,
- DMUB_EDID_CEA_DATA_CHUNK_BYTES + 1, &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_send_cea_dmub_unavailable - Test a failed DMUB command reports false
- * @test: KUnit test context
- */
-static void dm_test_send_cea_dmub_unavailable(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 data[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- /* ctx->dmub_srv is NULL, so the DMUB command execute fails. */
- ret = dm_edid_parser_send_cea(dm, 0, 8, data,
- DMUB_EDID_CEA_DATA_CHUNK_BYTES, &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_dmcu_empty - Test an empty extension parses to no VSDB
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_empty(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_dmcu(test, NULL);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[1] = {0};
-
- KUNIT_EXPECT_FALSE(test, parse_edid_cea_dmcu(dm, ext, 0, &vsdb));
-}
-
-/**
- * dm_test_parse_cea_dmcu_no_dmcu - Test a missing DMCU fails the first send
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_no_dmcu(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_dmcu(test, NULL);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- /* res_pool->dmcu is NULL, so the CEA send returns false. */
- ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_dmcu_vsdb_found - Test the DMCU reports an AMD VSDB
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_vsdb_found(struct kunit *test)
-{
- struct amdgpu_display_manager *dm =
- dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_vsdb);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_TRUE(test, ret);
- KUNIT_EXPECT_TRUE(test, vsdb.freesync_supported);
- KUNIT_EXPECT_EQ(test, vsdb.amd_vsdb_version, 2);
- KUNIT_EXPECT_EQ(test, vsdb.min_refresh_rate_hz, 24);
- KUNIT_EXPECT_EQ(test, vsdb.max_refresh_rate_hz, 60);
- KUNIT_EXPECT_EQ(test, vsdb.freesync_mccs_vcp_code, 0);
-}
-
-/**
- * dm_test_parse_cea_dmcu_vsdb_none - Test the DMCU finds no AMD VSDB
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_vsdb_none(struct kunit *test)
-{
- struct amdgpu_display_manager *dm =
- dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_novsdb);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_dmcu_multi_chunk - Test intermediate chunks are acked
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_multi_chunk(struct kunit *test)
-{
- struct amdgpu_display_manager *dm =
- dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_vsdb);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- ret = parse_edid_cea_dmcu(dm, ext, 2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_TRUE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_dmcu_ack_fail - Test a failed chunk ack aborts the parse
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmcu_ack_fail(struct kunit *test)
-{
- struct amdgpu_display_manager *dm =
- dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_ackfail);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- ret = parse_edid_cea_dmcu(dm, ext, 2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_dmub_empty - Test an empty extension returns the flag
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmub_empty(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[1] = {0};
-
- /* No chunks are sent, so the freesync flag is returned as-is. */
- vsdb.freesync_supported = true;
- KUNIT_EXPECT_TRUE(test, parse_edid_cea_dmub(dm, ext, 0, &vsdb));
-}
-
-/**
- * dm_test_parse_cea_dmub_send_fail - Test a chunk send failure aborts the parse
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_dmub_send_fail(struct kunit *test)
-{
- struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
- bool ret;
-
- /* The first chunk send fails (no DMUB), so the parse bails out. */
- ret = parse_edid_cea_dmub(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
- &vsdb);
- KUNIT_EXPECT_FALSE(test, ret);
-}
-
-/**
- * dm_test_parse_cea_routes_dmub - Test a present dmub_srv routes to DMUB
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_routes_dmub(struct kunit *test)
-{
- struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
- struct amdgpu_dm_connector *aconnector;
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[1] = {0};
-
- KUNIT_ASSERT_NOT_NULL(test, adev);
- mutex_init(&adev->dm.dc_lock);
- adev->dm.dmub_srv = kunit_kzalloc(test, 1, GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, adev->dm.dmub_srv);
-
- aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, aconnector);
- aconnector->base.dev = &adev->ddev;
-
- /* len 0 routes to the DMUB parser, which returns the freesync flag. */
- vsdb.freesync_supported = true;
- KUNIT_EXPECT_TRUE(test, parse_edid_cea(aconnector, ext, 0, &vsdb));
-}
-
-/**
- * dm_test_parse_cea_routes_dmcu - Test a missing dmub_srv routes to DMCU
- * @test: KUnit test context
- */
-static void dm_test_parse_cea_routes_dmcu(struct kunit *test)
-{
- struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
- struct amdgpu_dm_connector *aconnector;
- struct amdgpu_hdmi_vsdb_info vsdb = {0};
- u8 ext[1] = {0};
-
- KUNIT_ASSERT_NOT_NULL(test, adev);
- mutex_init(&adev->dm.dc_lock);
- adev->dm.dmub_srv = NULL;
-
- aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, aconnector);
- aconnector->base.dev = &adev->ddev;
-
- /* len 0 routes to the DMCU parser, which returns false. */
- KUNIT_EXPECT_FALSE(test, parse_edid_cea(aconnector, ext, 0, &vsdb));
-}
-
/**
* dm_test_get_amd_vsdb_unsupported - Test a zero VSDB version reports no support
* @test: The KUnit test context
@@ -8832,6 +8721,1033 @@ static void dm_test_frl_poll_retrains(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_test_frl_detect_calls, 1);
}
+/* Tests for amdgpu_dm_connector_init_helper() */
+
+/*
+ * Build an amdgpu_dm_connector on a kunit drm_device embedded in an
+ * amdgpu_device, with the amdgpu mode properties created exactly as
+ * amdgpu_dm_mode_config_init() does so the helper has real properties to
+ * attach. The dc_link carries a link encoder and leaves DIG mapping
+ * inflexible, so link_enc_cfg_get_link_enc() resolves without a dc instance.
+ */
+struct dm_test_init_helper_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_display_manager *dm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+};
+
+/*
+ * Stand in for amdgpu_display_modeset_create_props(), which the test module
+ * cannot link against. Only the properties the init helper attaches are
+ * created; underscan is a plain range because only attachment is under test.
+ */
+static void dm_test_create_mode_props(struct kunit *test, struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct drm_device *drm = adev_to_drm(adev);
+
+ KUNIT_ASSERT_EQ(test, drm_mode_create_scaling_mode_property(drm), 0);
+
+ mode_info->underscan_property =
+ drm_property_create_range(drm, 0, "underscan", 0, 1);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_property);
+ mode_info->underscan_hborder_property =
+ drm_property_create_range(drm, 0, "underscan hborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_hborder_property);
+ mode_info->underscan_vborder_property =
+ drm_property_create_range(drm, 0, "underscan vborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_vborder_property);
+}
+
+static struct dm_test_init_helper_ctx *
+dm_test_init_helper_ctx_alloc(struct kunit *test, int connector_type)
+{
+ struct dm_test_init_helper_ctx *ctx;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dev = dev;
+ dm_test_create_mode_props(test, ctx->adev);
+
+ ctx->dm = &ctx->adev->dm;
+ ctx->dm->adev = ctx->adev;
+ ctx->dm->ddev = ctx->drm;
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_test_connector_funcs, connector_type,
+ NULL), 0);
+
+ return ctx;
+}
+
+/* True when @prop is attached to the connector's mode object. */
+static bool dm_test_has_prop(struct drm_connector *connector, struct drm_property *prop)
+{
+ struct drm_object_properties *props = connector->base.properties;
+ int i;
+
+ if (!prop)
+ return false;
+
+ for (i = 0; i < props->count; i++)
+ if (props->properties[i] == prop)
+ return true;
+
+ return false;
+}
+
+/**
+ * dm_test_init_helper_common_defaults - Test the connector defaults and properties
+ * @test: The KUnit test context
+ *
+ * The helper resets the connector state, records the link and its index, and
+ * attaches the scaling mode and the three underscan properties that every
+ * connector type receives.
+ */
+static void dm_test_init_helper_common_defaults(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 3);
+
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->connector_id, 3);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->bl_idx, -1);
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_link, ctx->link);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->audio_inst, -1);
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->pack_sdp_v1_3);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->as_type, (int)ADAPTIVE_SYNC_TYPE_NONE);
+ KUNIT_EXPECT_FALSE(test, connector->interlace_allowed);
+ KUNIT_EXPECT_FALSE(test, connector->doublescan_allowed);
+ KUNIT_EXPECT_FALSE(test, connector->stereo_allowed);
+ KUNIT_EXPECT_EQ(test, connector->dpms, DRM_MODE_DPMS_OFF);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->hpd.hpd, (int)AMDGPU_HPD_NONE);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->hdmi_hpd_debounce_delay_ms, 0);
+
+ /* The link encoder advertises no YCbCr 4:2:0 support. */
+ KUNIT_EXPECT_FALSE(test, connector->ycbcr_420_allowed);
+
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.scaling_mode_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->adev->mode_info.underscan_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->adev->mode_info.underscan_hborder_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->adev->mode_info.underscan_vborder_property));
+}
+
+/**
+ * dm_test_init_helper_hdmi - Test the HDMI connector wiring
+ * @test: The KUnit test context
+ *
+ * HDMI polls on hotplug, takes YCbCr 4:2:0 support straight from the link
+ * encoder features and gets the max bpc, content type, colorspace, HDR
+ * metadata and VRR capable properties.
+ */
+static void dm_test_init_helper_hdmi(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->link_enc->features.hdmi_ycbcr420_supported = true;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_TRUE(test, connector->ycbcr_420_allowed);
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, connector->state->max_bpc, 16);
+ KUNIT_EXPECT_EQ(test, connector->state->max_requested_bpc, 16);
+ KUNIT_EXPECT_NOT_NULL(test, connector->max_bpc_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.content_type_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->drm->mode_config.hdr_output_metadata_property));
+}
+
+/**
+ * dm_test_init_helper_dp - Test the DisplayPort connector wiring
+ * @test: The KUnit test context
+ *
+ * DisplayPort re-resolves the link encoder through the encoder configuration
+ * and takes YCbCr 4:2:0 support from its DP feature bit.
+ */
+static void dm_test_init_helper_dp(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->link_enc->features.dp_ycbcr420_supported = true;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DisplayPort, ctx->link, 1);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_TRUE(test, connector->ycbcr_420_allowed);
+ KUNIT_EXPECT_NOT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_dp_mst_root - Test an MST branch connector skips properties
+ * @test: The KUnit test context
+ *
+ * A connector below an MST root gets neither the broadcast RGB, max bpc,
+ * colorspace nor VRR capable property, because those live on the root.
+ */
+static void dm_test_init_helper_dp_mst_root(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->aconnector->mst_root = ctx->aconnector;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DisplayPort, ctx->link, 0);
+
+ KUNIT_EXPECT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NULL(test, connector->max_bpc_property);
+ KUNIT_EXPECT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NULL(test, connector->vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_dvid - Test DVI-D polls on hotplug
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_dvid(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DVID);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DVID, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->base.ycbcr_420_allowed);
+}
+
+/**
+ * dm_test_init_helper_vga - Test VGA polls on connect and disconnect
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_vga(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_VGA);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_VGA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled,
+ (int)(DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT));
+}
+
+/**
+ * dm_test_init_helper_unpolled_default - Test an unhandled type is left unpolled
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_unpolled_default(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_Composite);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_Composite, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled, 0);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->base.colorspace_property);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->base.vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_edp - Test eDP gets the panel type property
+ * @test: The KUnit test context
+ *
+ * eDP shares the DisplayPort colorspace and HDR property set and additionally
+ * receives the panel type property. No privacy screen provider is registered
+ * in the test environment, so the lookup fails with -ENODEV and is ignored.
+ */
+static void dm_test_init_helper_edp(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_eDP, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, 0);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.panel_type_property));
+ KUNIT_EXPECT_NULL(test, connector->privacy_screen);
+}
+
+/**
+ * dm_test_init_helper_hdcp_property - Test the content protection property
+ * @test: The KUnit test context
+ *
+ * The content protection property is only attached when a HDCP workqueue was
+ * created for the device.
+ */
+static void dm_test_init_helper_hdcp_property(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->adev->dm.hdcp_workqueue = kunit_kzalloc(test, sizeof(struct hdcp_workqueue),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->adev->dm.hdcp_workqueue);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->drm->mode_config.content_protection_property));
+}
+
+/**
+ * dm_test_init_helper_hpd_debounce_disabled - Test the default HPD debounce delay
+ * @test: The KUnit test context
+ *
+ * With the hdmi_hpd_debounce_delay_ms module parameter left at its default the
+ * debounce work is not armed and the delay stays zero.
+ */
+static void dm_test_init_helper_hpd_debounce_disabled(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->hdmi_hpd_debounce_delay_ms, 0);
+}
+
+/* Tests for amdgpu_dm_initialize_hdmi_connector() */
+
+/**
+ * dm_test_initialize_hdmi_cec_registers - Test the CEC notifier is registered
+ * @test: The KUnit test context
+ *
+ * Without DC_DISABLE_HDMI_CEC in the debug mask a CEC notifier is created for
+ * the connector.
+ */
+static void dm_test_initialize_hdmi_cec_registers(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_initialize_hdmi_connector(ctx->aconnector), 0);
+ KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->notifier);
+}
+
+/* Tests for amdgpu_dm_update_freesync_caps() */
+
+static void dm_test_fs_free_edid(void *data)
+{
+ drm_edid_free(data);
+}
+
+/*
+ * Build a two block EDID: the minimal base block with its extension count set
+ * to one, followed by @ext, with both checksums recomputed so drm_edid_raw()
+ * and the DRM EDID parsers accept it.
+ */
+static const struct drm_edid *dm_test_fs_edid_alloc(struct kunit *test, const u8 *ext)
+{
+ const struct drm_edid *drm_edid;
+ u8 *raw;
+ int i;
+
+ raw = kunit_kzalloc(test, 2 * EDID_LENGTH, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, raw);
+ memcpy(raw, dm_test_uad_edid, EDID_LENGTH);
+ memcpy(raw + EDID_LENGTH, ext, EDID_LENGTH);
+ raw[EDID_LENGTH - 2] = 1;
+
+ for (i = 0; i < 2; i++) {
+ u8 *block = raw + i * EDID_LENGTH;
+ u8 sum = 0;
+ int j;
+
+ for (j = 0; j < EDID_LENGTH - 1; j++)
+ sum += block[j];
+ block[EDID_LENGTH - 1] = -sum;
+ }
+
+ drm_edid = drm_edid_alloc(raw, 2 * EDID_LENGTH);
+ KUNIT_ASSERT_NOT_NULL(test, drm_edid);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_fs_free_edid,
+ (void *)drm_edid), 0);
+
+ return drm_edid;
+}
+
+/*
+ * A DisplayID extension holding a dynamic video timing range descriptor, which
+ * is what parse_edid_displayid_vrr() scans for.
+ */
+static const struct drm_edid *
+dm_test_fs_edid_displayid(struct kunit *test, u8 min_vfreq, u8 max_vfreq)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_DISPLAYID_EXT;
+ ext[1] = 0x25;
+ ext[2] = 0x00;
+ ext[3] = 9;
+ ext[10] = min_vfreq;
+ ext[11] = max_vfreq;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+/*
+ * A CTA-861 extension with no data blocks, enough for parse_hdmi_amd_vsdb() to
+ * accept the block and hand it to the (mocked) DMCU parser.
+ */
+static const struct drm_edid *dm_test_fs_edid_cea(struct kunit *test)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_CEA_EXT;
+ ext[1] = 3;
+ ext[2] = 4;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+/*
+ * A CTA-861 extension carrying a 15-byte AMD VSDB v3 payload, which
+ * drm_parse_amd_vsdb() turns into connector->display_info.amd_vsdb and
+ * get_amd_vsdb() then reads back.
+ */
+static const struct drm_edid *
+dm_test_fs_edid_amd_vsdb(struct kunit *test, u8 feature_caps)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_CEA_EXT;
+ ext[1] = 3;
+ ext[2] = 4 + 1 + 15;
+ ext[4] = (3 << 5) | 15; /* vendor data block, 15-byte payload */
+ ext[5] = 0x1a; /* AMD IEEE OUI, LSB first */
+ ext[8] = 0x03; /* AMD VSDB payload version */
+ ext[9] = feature_caps;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+struct dm_test_fs_caps_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+ struct dc_sink *sink;
+ struct resource_pool *pool;
+};
+
+/*
+ * Build a connector that clears every guard at the top of
+ * amdgpu_dm_update_freesync_caps(): a reset connector state, a dc_sink whose
+ * dc_context reports a VRR capable DCE version, and a non-NULL freesync
+ * module. The resource pool carries no DMCU, so tests that need the AMD VSDB
+ * parser to succeed install one.
+ */
+static struct dm_test_fs_caps_ctx *
+dm_test_fs_caps_ctx_alloc(struct kunit *test, enum signal_type sink_signal)
+{
+ struct dm_test_fs_caps_ctx *ctx;
+ struct dc_context *dc_ctx;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dm.adev = ctx->adev;
+ mutex_init(&ctx->adev->dm.dc_lock);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_test_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL), 0);
+ amdgpu_dm_connector_funcs_reset(&ctx->aconnector->base);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector->base.state);
+ KUNIT_ASSERT_EQ(test,
+ drm_connector_attach_vrr_capable_property(&ctx->aconnector->base), 0);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
+ dc_ctx->driver_context = ctx->adev;
+ dc_ctx->dce_version = DCE_VERSION_8_0;
+
+ ctx->pool = kunit_kzalloc(test, sizeof(*ctx->pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->pool);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ dc->ctx = dc_ctx;
+ dc->res_pool = ctx->pool;
+ ctx->adev->dm.dc = dc;
+
+ ctx->adev->dm.freesync_module =
+ kunit_kzalloc(test, sizeof(struct mod_freesync), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->adev->dm.freesync_module);
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->aconnector->dc_link = ctx->link;
+
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ ctx->sink->ctx = dc_ctx;
+ ctx->sink->sink_signal = sink_signal;
+ ctx->aconnector->dc_sink = ctx->sink;
+
+ return ctx;
+}
+
+static bool dm_test_fs_caps_capable(struct dm_test_fs_caps_ctx *ctx)
+{
+ return to_dm_connector_state(ctx->aconnector->base.state)->freesync_capable;
+}
+
+/**
+ * dm_test_fs_caps_dp_msa_range - Test a DP sink with an invalid-MSA range
+ * @test: The KUnit test context
+ *
+ * A DisplayPort sink allowing invalid MSA timing takes its refresh range from
+ * the monitor range that parse_edid_displayid_vrr() recovered, and a range
+ * wider than 10Hz marks the connector FreeSync capable.
+ */
+static void dm_test_fs_caps_dp_msa_range(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 40);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 144);
+ KUNIT_EXPECT_TRUE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_dp_narrow_range - Test a range of 10Hz or less is rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_fs_caps_dp_narrow_range(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 60, 65);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 60);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 65);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_dp_msa_not_allowed - Test a DP sink requiring valid MSA
+ * @test: The KUnit test context
+ *
+ * Without allow_invalid_MSA_timing_param the reported range is ignored and the
+ * connector keeps a zero refresh range.
+ */
+static void dm_test_fs_caps_dp_msa_not_allowed(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 0);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 0);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_edp_replay_mode - Test an eDP panel advertising replay
+ * @test: The KUnit test context
+ *
+ * An AMD VSDB with the replay feature bit set records the replay mode and its
+ * VSDB version on the connector and selects the eDP adaptive sync type.
+ */
+static void dm_test_fs_caps_edp_replay_mode(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_EDP);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_amd_vsdb(test, 0x40);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_TRUE(test, ctx->aconnector->vsdb_info.replay_mode);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->vsdb_info.amd_vsdb_version, 3);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->as_type, (int)ADAPTIVE_SYNC_TYPE_EDP);
+}
+
+/**
+ * dm_test_fs_caps_hdmi_no_vsdb - Test an HDMI sink with no AMD VSDB
+ * @test: The KUnit test context
+ *
+ * Without a DMCU the CEA parse fails, so no refresh range is recorded.
+ */
+static void dm_test_fs_caps_hdmi_no_vsdb(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_cea(test);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->vsdb_info.freesync_supported);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 0);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_force_min_hz_quirk - Test the forced FreeSync minimum quirk
+ * @test: The KUnit test context
+ *
+ * A quirked panel overrides the minimum refresh rate on both the connector and
+ * the published monitor range once FreeSync is otherwise supported.
+ */
+static void dm_test_fs_caps_force_min_hz_quirk(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+ ctx->sink->edid_caps.panel_patch.force_freesync_min_hz = 50;
+
+ amdgpu_dm_update_freesync_caps(connector, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 50);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.min_vfreq, 50);
+}
+
+/**
+ * dm_test_fs_caps_mccs_clears_capability - Test MCCS withdraws FreeSync support
+ * @test: The KUnit test context
+ *
+ * When the sink advertises a FreeSync VCP code but MCCS reports no support,
+ * the connector loses its FreeSync capability.
+ */
+static void dm_test_fs_caps_mccs_clears_capability(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+ /* A non-DP, non-HDMI link keeps dm_helpers_read_mccs_caps() off the wire. */
+ ctx->link->connector_signal = SIGNAL_TYPE_VIRTUAL;
+ ctx->sink->edid_caps.freesync_vcp_code = 0x60;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, true);
+
+ KUNIT_EXPECT_FALSE(test, ctx->sink->mccs_caps.freesync_supported);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_disables_replay - Test replay is dropped without FreeSync
+ * @test: The KUnit test context
+ *
+ * A link advertising replay support has it withdrawn when the connector ends
+ * up without FreeSync capability.
+ */
+static void dm_test_fs_caps_disables_replay(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->replay_settings.config.replay_supported = true;
+ ctx->link->replay_settings.replay_feature_enabled = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_FALSE(test, ctx->link->replay_settings.config.replay_supported);
+ KUNIT_EXPECT_FALSE(test, ctx->link->replay_settings.replay_feature_enabled);
+}
+
+/* Tests for amdgpu_dm_connector_init() and the get_modes() helper hook */
+
+/*
+ * amdgpu_dm_create_i2c() parents the adapter on adev->pdev->dev, so
+ * devm_i2c_add_adapter() needs a registered device there. Provide one by
+ * registering the device embedded in a KUnit allocated pci_dev.
+ */
+static void dm_test_conn_init_release_dev(struct device *dev)
+{
+ /* Backing storage is KUnit managed, so there is nothing to free. */
+}
+
+static void dm_test_conn_init_unregister_dev(void *data)
+{
+ device_unregister(data);
+}
+
+struct dm_test_conn_init_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_display_manager *dm;
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_encoder *aencoder;
+ struct dc_link *link;
+};
+
+static struct dm_test_conn_init_ctx *
+dm_test_conn_init_ctx_alloc(struct kunit *test, enum signal_type signal)
+{
+ struct dm_test_conn_init_ctx *ctx;
+ struct link_service *link_srv;
+ struct dc_context *dc_ctx;
+ struct ddc_service *ddc;
+ struct pci_dev *pdev;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dev = dev;
+ ctx->adev->mode_info.num_crtc = 1;
+ dm_test_create_mode_props(test, ctx->adev);
+
+ pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pdev);
+ device_initialize(&pdev->dev);
+ pdev->dev.parent = dev;
+ pdev->dev.release = dm_test_conn_init_release_dev;
+ KUNIT_ASSERT_EQ(test, dev_set_name(&pdev->dev, "dm-test-i2c-parent"), 0);
+ KUNIT_ASSERT_EQ(test, device_add(&pdev->dev), 0);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_conn_init_unregister_dev,
+ &pdev->dev), 0);
+ ctx->adev->pdev = pdev;
+
+ ctx->dm = &ctx->adev->dm;
+ ctx->dm->adev = ctx->adev;
+ ctx->dm->ddev = ctx->drm;
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
+ dc_ctx->driver_context = ctx->adev;
+
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ link_srv->dp_get_encoding_format = dm_test_gm_enc_8b10b;
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ dc->ctx = dc_ctx;
+ dc->link_srv = link_srv;
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->connector_signal = signal;
+ ctx->link->dc = dc;
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
+ ddc->ctx = dc_ctx;
+ ddc->link = ctx->link;
+ ctx->link->ddc = ddc;
+
+ dc->links[0] = ctx->link;
+ dc->link_count = 1;
+ ctx->dm->dc = dc;
+
+ /* amdgpu_dm_connector_destroy() and amdgpu_dm_encoder_destroy() kfree() these. */
+ ctx->aconnector = kzalloc_obj(*ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ ctx->aencoder = kzalloc_obj(*ctx->aencoder);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aencoder);
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_encoder_init(ctx->drm, ctx->aencoder, 0), 0);
+
+ return ctx;
+}
+
+/**
+ * dm_test_conn_init_hdmi - Test a HDMI connector is fully brought up
+ * @test: The KUnit test context
+ *
+ * The DC link is bound to the connector, an i2c adapter is created and
+ * registered as the DDC bus, the DRM connector is initialized with the DM
+ * funcs and helpers, the encoder is attached and the CEC notifier registered.
+ */
+static void dm_test_conn_init_hdmi(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ KUNIT_EXPECT_PTR_EQ(test, ctx->link->priv, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector->i2c);
+ KUNIT_EXPECT_PTR_EQ(test, connector->ddc, &ctx->aconnector->i2c->base);
+ KUNIT_EXPECT_EQ(test, connector->connector_type, DRM_MODE_CONNECTOR_HDMIA);
+ KUNIT_EXPECT_NOT_NULL(test, connector->helper_private);
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_link, ctx->link);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->connector_id, 0);
+ KUNIT_EXPECT_EQ(test, connector->possible_encoders,
+ drm_encoder_mask(&ctx->aencoder->base));
+ KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->notifier);
+}
+
+/**
+ * dm_test_conn_init_dvi - Test a DVI link maps to a DVI-D connector
+ * @test: The KUnit test context
+ *
+ * A single link DVI signal is not HDMI, so no CEC notifier is registered.
+ */
+static void dm_test_conn_init_dvi(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_DVI_SINGLE_LINK);
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->base.connector_type,
+ DRM_MODE_CONNECTOR_DVID);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->notifier);
+}
+
+/**
+ * dm_test_conn_init_get_modes_hook - Test the installed get_modes helper
+ * @test: The KUnit test context
+ *
+ * The connector helper funcs that amdgpu_dm_connector_init() installs forward
+ * mode enumeration to amdgpu_dm_connector_get_modes(), which synthesizes the
+ * no-EDID fallback modes.
+ */
+static void dm_test_conn_init_get_modes_hook(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ const struct drm_connector_helper_funcs *helper;
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ helper = connector->helper_private;
+ KUNIT_ASSERT_NOT_NULL(test, helper);
+ KUNIT_ASSERT_NOT_NULL(test, helper->get_modes);
+
+ KUNIT_EXPECT_GT(test, helper->get_modes(connector), 0);
+ KUNIT_EXPECT_GT(test, ctx->aconnector->num_modes, 0);
+}
+
+/* Tests for dm_force_atomic_commit() */
+
+/* Fails the very first state duplication so the error path is taken. */
+static struct drm_connector_state *
+dm_test_force_dup_state_fail(struct drm_connector *connector)
+{
+ return NULL;
+}
+
+static const struct drm_connector_funcs dm_test_force_fail_funcs = {
+ .reset = amdgpu_dm_connector_funcs_reset,
+ .atomic_duplicate_state = dm_test_force_dup_state_fail,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* The atomic modeset check dereferences the helper funcs unconditionally. */
+static int dm_test_force_get_modes(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_helper_funcs dm_test_force_conn_helper_funcs = {
+ .get_modes = dm_test_force_get_modes,
+};
+
+struct dm_test_force_ctx {
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_modeset_acquire_ctx acquire_ctx;
+};
+
+static void dm_test_force_drop_locks(void *data)
+{
+ struct dm_test_force_ctx *ctx = data;
+
+ ctx->drm->mode_config.acquire_ctx = NULL;
+ drm_modeset_drop_locks(&ctx->acquire_ctx);
+ drm_modeset_acquire_fini(&ctx->acquire_ctx);
+}
+
+/*
+ * Build a disabled but fully initialized pipe: a primary plane, a CRTC (whose
+ * drm_crtc is the first member of amdgpu_crtc, so to_amdgpu_crtc() resolves)
+ * and a connector wired to an encoder that still points at the CRTC, which is
+ * the state dm_force_atomic_commit() is asked to restore.
+ */
+static struct dm_test_force_ctx *
+dm_test_force_ctx_alloc(struct kunit *test, const struct drm_connector_funcs *funcs)
+{
+ struct dm_test_force_ctx *ctx;
+ struct drm_encoder *encoder;
+ struct drm_plane *primary;
+ struct drm_crtc *crtc;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ primary = drm_kunit_helper_create_primary_plane(test, ctx->drm, NULL, NULL,
+ NULL, 0, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ crtc = drm_kunit_helper_create_crtc(test, ctx->drm, primary, NULL, NULL, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base, funcs,
+ DRM_MODE_CONNECTOR_HDMIA, NULL), 0);
+ drm_connector_helper_add(&ctx->aconnector->base, &dm_test_force_conn_helper_funcs);
+
+ encoder = drmm_kzalloc(ctx->drm, sizeof(*encoder), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, encoder);
+ KUNIT_ASSERT_EQ(test,
+ drmm_encoder_init(ctx->drm, encoder, NULL,
+ DRM_MODE_ENCODER_TMDS, NULL), 0);
+ encoder->crtc = crtc;
+ ctx->aconnector->base.encoder = encoder;
+
+ drm_mode_config_reset(ctx->drm);
+
+ drm_modeset_acquire_init(&ctx->acquire_ctx, 0);
+ ctx->drm->mode_config.acquire_ctx = &ctx->acquire_ctx;
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_force_drop_locks, ctx), 0);
+
+ return ctx;
+}
+
+/**
+ * dm_test_force_commit_succeeds - Test the forced restore commits the pipe
+ * @test: The KUnit test context
+ *
+ * The connector, its CRTC and the CRTC primary plane are pulled into a fresh
+ * atomic state, the CRTC is marked as needing a modeset and the commit
+ * succeeds.
+ */
+static void dm_test_force_commit_succeeds(struct kunit *test)
+{
+ struct dm_test_force_ctx *ctx =
+ dm_test_force_ctx_alloc(test, &dm_test_connector_funcs);
+
+ KUNIT_EXPECT_EQ(test, dm_force_atomic_commit(&ctx->aconnector->base), 0);
+}
+
+/**
+ * dm_test_force_commit_conn_state_error - Test a failed connector state duplication
+ * @test: The KUnit test context
+ *
+ * When the connector state cannot be duplicated the error is propagated and
+ * the partially built atomic state is released without committing.
+ */
+static void dm_test_force_commit_conn_state_error(struct kunit *test)
+{
+ struct dm_test_force_ctx *ctx =
+ dm_test_force_ctx_alloc(test, &dm_test_force_fail_funcs);
+
+ KUNIT_EXPECT_EQ(test, dm_force_atomic_commit(&ctx->aconnector->base), -ENOMEM);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -9055,6 +9971,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_create_stream_virtual_signal),
KUNIT_CASE(dm_test_create_stream_scaling_src),
KUNIT_CASE(dm_test_create_stream_existing_sink),
+ KUNIT_CASE(dm_test_create_stream_preferred_mode),
+ KUNIT_CASE(dm_test_create_stream_scaled_keeps_refresh),
+ KUNIT_CASE(dm_test_create_stream_timing_override),
+ KUNIT_CASE(dm_test_create_stream_dp_vsc_colorimetry),
+ KUNIT_CASE(dm_test_create_stream_dp_colorimetry_quirk),
+ KUNIT_CASE(dm_test_create_stream_hdmi_vsif),
/* amdgpu_dm_connector_detect */
KUNIT_CASE(dm_test_detect_force_on),
KUNIT_CASE(dm_test_detect_force_on_digital),
@@ -9155,18 +10077,6 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_restore_state_no_encoder),
KUNIT_CASE(dm_test_restore_state_no_stream),
KUNIT_CASE(dm_test_restore_state_same_sink),
- KUNIT_CASE(dm_test_send_cea_length_too_long),
- KUNIT_CASE(dm_test_send_cea_dmub_unavailable),
- KUNIT_CASE(dm_test_parse_cea_dmcu_empty),
- KUNIT_CASE(dm_test_parse_cea_dmcu_no_dmcu),
- KUNIT_CASE(dm_test_parse_cea_dmcu_vsdb_found),
- KUNIT_CASE(dm_test_parse_cea_dmcu_vsdb_none),
- KUNIT_CASE(dm_test_parse_cea_dmcu_multi_chunk),
- KUNIT_CASE(dm_test_parse_cea_dmcu_ack_fail),
- KUNIT_CASE(dm_test_parse_cea_dmub_empty),
- KUNIT_CASE(dm_test_parse_cea_dmub_send_fail),
- KUNIT_CASE(dm_test_parse_cea_routes_dmub),
- KUNIT_CASE(dm_test_parse_cea_routes_dmcu),
/* get_amd_vsdb */
KUNIT_CASE(dm_test_get_amd_vsdb_unsupported),
KUNIT_CASE(dm_test_get_amd_vsdb_supported),
@@ -9221,6 +10131,35 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_frl_skips_zero_rate),
KUNIT_CASE(dm_test_frl_poll_no_update),
KUNIT_CASE(dm_test_frl_poll_retrains),
+ /* amdgpu_dm_connector_init_helper */
+ KUNIT_CASE(dm_test_init_helper_common_defaults),
+ KUNIT_CASE(dm_test_init_helper_hdmi),
+ KUNIT_CASE(dm_test_init_helper_dp),
+ KUNIT_CASE(dm_test_init_helper_dp_mst_root),
+ KUNIT_CASE(dm_test_init_helper_dvid),
+ KUNIT_CASE(dm_test_init_helper_vga),
+ KUNIT_CASE(dm_test_init_helper_unpolled_default),
+ KUNIT_CASE(dm_test_init_helper_edp),
+ KUNIT_CASE(dm_test_init_helper_hdcp_property),
+ KUNIT_CASE(dm_test_init_helper_hpd_debounce_disabled),
+ /* amdgpu_dm_initialize_hdmi_connector */
+ KUNIT_CASE(dm_test_initialize_hdmi_cec_registers),
+ /* amdgpu_dm_update_freesync_caps */
+ KUNIT_CASE(dm_test_fs_caps_dp_msa_range),
+ KUNIT_CASE(dm_test_fs_caps_dp_narrow_range),
+ KUNIT_CASE(dm_test_fs_caps_dp_msa_not_allowed),
+ KUNIT_CASE(dm_test_fs_caps_edp_replay_mode),
+ KUNIT_CASE(dm_test_fs_caps_hdmi_no_vsdb),
+ KUNIT_CASE(dm_test_fs_caps_force_min_hz_quirk),
+ KUNIT_CASE(dm_test_fs_caps_mccs_clears_capability),
+ KUNIT_CASE(dm_test_fs_caps_disables_replay),
+ /* amdgpu_dm_connector_init */
+ KUNIT_CASE(dm_test_conn_init_hdmi),
+ KUNIT_CASE(dm_test_conn_init_dvi),
+ KUNIT_CASE(dm_test_conn_init_get_modes_hook),
+ /* dm_force_atomic_commit */
+ KUNIT_CASE(dm_test_force_commit_succeeds),
+ KUNIT_CASE(dm_test_force_commit_conn_state_error),
{}
};
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
index 9b15f53a9c62..4668dc362544 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
@@ -439,7 +439,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test)
* dm_test_crtc_set_vupdate_irq_dc_busy - Test vupdate irq when DC rejects request
* @test: The KUnit test context
*
- * With an OTG instance assigned but no DC attached, dc_interrupt_set() returns
+ * With an OTG instance assigned but no DC attached, amdgpu_dm_irq_set() returns
* false and the function must report the request as busy (-EBUSY).
*/
static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
@@ -456,12 +456,12 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
acrtc->base.dev = &adev->ddev;
acrtc->otg_inst = 0;
- /* adev->dm.dc is NULL, so dc_interrupt_set() returns false. */
+ /* adev->dm.dc is NULL, so amdgpu_dm_irq_set() returns false. */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true), -EBUSY);
}
-/* Per-source funcs let dc_interrupt_set() succeed without register access. */
+/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
static bool dm_test_vupdate_irq_src_set(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
@@ -480,7 +480,7 @@ static struct irq_source_info_funcs dm_test_vupdate_irq_src_funcs = {
.ack = dm_test_vupdate_irq_src_ack,
};
-/* A .set that fails so dc_interrupt_set() reports the source as busy. */
+/* A .set that fails so amdgpu_dm_irq_set() reports the source as busy. */
static bool dm_test_vupdate_irq_src_set_busy(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
@@ -522,7 +522,9 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test)
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
- /* Populate the per-source info table so dc_interrupt_set() succeeds. */
+ /*
+ * Populate the per-source info table so amdgpu_dm_irq_set() succeeds.
+ */
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
@@ -1021,7 +1023,9 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test)
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
- /* Per-source .set fails so dc_interrupt_set() reports the source busy. */
+ /*
+ * Per-source .set fails so amdgpu_dm_irq_set() reports the source busy.
+ */
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
@@ -1662,7 +1666,7 @@ static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test)
old->stream = stream;
crtc->state = &old->base;
- amdgpu_dm_crtc_reset_state(crtc);
+ amdgpu_dm_crtc_create_state(crtc);
/* Old state was destroyed (stream ref dropped) and a new one installed. */
KUNIT_EXPECT_EQ(test, kref_read(&stream->refcount), 1);
@@ -2639,6 +2643,7 @@ static struct kunit_case amdgpu_dm_crtc_tests[] = {
KUNIT_CASE(dm_test_crtc_destroy_cleans_up_and_frees),
/* amdgpu_dm_crtc_create_state */
KUNIT_CASE(dm_test_crtc_create_state_allocates_state),
+ KUNIT_CASE(dm_test_crtc_reset_state_replaces_existing),
/* amdgpu_dm_crtc_destroy_state */
KUNIT_CASE(dm_test_crtc_destroy_state_no_stream),
KUNIT_CASE(dm_test_crtc_destroy_state_releases_stream),
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
index ded0f680296f..51c3995de76d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
@@ -2594,17 +2594,21 @@ static void dm_test_is_dp_sink_present_null_priv(struct kunit *test)
* dm_test_dmub_outbox_interrupt_control_null_dc - Test outbox irq control with NULL dc
* @test: The KUnit test context
*
- * dc_interrupt_set() is NULL-safe and returns false when dc is NULL, so the
+ * amdgpu_dm_irq_set() is NULL-safe and returns false when dc is NULL, so the
* helper returns false without touching real interrupt hardware.
*/
static void dm_test_dmub_outbox_interrupt_control_null_dc(struct kunit *test)
{
+ struct amdgpu_device *adev;
struct dc_context *ctx;
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ctx);
+ ctx->driver_context = adev;
- /* ctx->dc is NULL → dc_interrupt_set returns false */
+ /* adev->dm.dc is NULL → amdgpu_dm_irq_set returns false */
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, true));
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, false));
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index af4eb29faeed..dc7d94f75ff4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -360,7 +360,7 @@ static bool dm_test_irq_src_ack(struct irq_service *irq_service,
return true;
}
-/* Per-source funcs let dc_interrupt_set() succeed without register access. */
+/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
static struct irq_source_info_funcs dm_test_irq_src_funcs = {
.set = dm_test_irq_src_set,
.ack = dm_test_irq_src_ack,
@@ -382,7 +382,7 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
/*
- * Populate the per-source info table so dc_interrupt_set()/_ack()
+ * Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
* succeed without touching hardware registers.
*/
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
@@ -1351,7 +1351,7 @@ static void dm_test_irq_suspend_empty(struct kunit *test)
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
/*
- * With no registered handlers the HW dc_interrupt_set() calls are
+ * With no registered handlers the amdgpu_dm_irq_set() calls are
* skipped, so suspend must complete without touching the (absent) DC.
*/
amdgpu_dm_irq_suspend(adev);
@@ -1399,11 +1399,11 @@ static void dm_test_irq_resume_late_empty(struct kunit *test)
}
/**
- * dm_test_irq_suspend_registered - Test suspend reaches the dc_interrupt_set path
+ * dm_test_irq_suspend_registered - Test suspend reaches the irq set path
* @test: The KUnit test context
*
* Registers a low-context HPD handler so the handler list is non-empty,
- * forcing amdgpu_dm_irq_suspend() to call dc_interrupt_set() (NULL-safe with
+ * forcing amdgpu_dm_irq_suspend() to call amdgpu_dm_irq_set() (NULL-safe with
* no DC) and flush_work() on the registered handler.
*/
static void dm_test_irq_suspend_registered(struct kunit *test)
@@ -1454,11 +1454,11 @@ static void dm_test_irq_suspend_disables_polling(struct kunit *test)
}
/**
- * dm_test_irq_resume_early_registered - Test early resume reaches dc_interrupt_set
+ * dm_test_irq_resume_early_registered - Test early resume reaches irq set
* @test: The KUnit test context
*
* Registers a low-context HPD RX handler so early resume calls
- * dc_interrupt_set() for the short-pulse interrupt source.
+ * amdgpu_dm_irq_set() for the short-pulse interrupt source.
*/
static void dm_test_irq_resume_early_registered(struct kunit *test)
{
@@ -1482,10 +1482,10 @@ static void dm_test_irq_resume_early_registered(struct kunit *test)
}
/**
- * dm_test_irq_resume_late_registered - Test late resume reaches dc_interrupt_set
+ * dm_test_irq_resume_late_registered - Test late resume reaches irq set
* @test: The KUnit test context
*
- * Registers a low-context HPD handler so late resume calls dc_interrupt_set()
+ * Registers a low-context HPD handler so late resume calls amdgpu_dm_irq_set()
* for the HPD interrupt source.
*/
static void dm_test_irq_resume_late_registered(struct kunit *test)
@@ -1716,7 +1716,7 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
/*
* otg_inst >= 0 computes the irq source and reaches the NULL-safe
- * dc_interrupt_set(); the ips_support branch is skipped (dc == NULL).
+ * amdgpu_dm_irq_set(); the ips_support branch is skipped (dc == NULL).
*/
acrtc->otg_inst = 3;
adev->mode_info.crtcs[0] = acrtc;
@@ -1795,8 +1795,8 @@ static void dm_test_set_vupdate_irq_state_enable(struct kunit *test)
*
* With a non-NULL DC that advertises IPS support and currently allows idle
* optimizations, dm_irq_state() must call dc_allow_idle_optimizations() before
- * dc_interrupt_set(). disable_idle_power_optimizations makes that call a safe
- * early return, and per-source stub funcs let dc_interrupt_set() succeed.
+ * amdgpu_dm_irq_set(). disable_idle_power_optimizations makes that call a safe
+ * early return, and per-source stub funcs let amdgpu_dm_irq_set() succeed.
*/
static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
{
@@ -2048,7 +2048,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- /* dc_interrupt_set() is a no-op when dc is NULL, so both states
+ /* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
* return 0 without dereferencing the (absent) DC.
*/
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
@@ -2108,7 +2108,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- /* Single dc_interrupt_set() call must be skipped when dc is NULL. */
+ /* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
amdgpu_dm_outbox_init(adev);
}
@@ -2126,7 +2126,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test)
/*
* With an empty connector list the per-connector loop is skipped and
- * the initial clear loop relies on dc_interrupt_set() being a no-op
+ * the initial clear loop relies on amdgpu_dm_irq_set() being a no-op
* for a NULL dc, so init must complete without touching the DC.
*/
amdgpu_dm_hpd_init(adev);
@@ -2161,7 +2161,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
/*
* num_hpd = 0 forces irq_type >= num_hpd so the loop takes the HW
- * fallback (dc_interrupt_set()) instead of amdgpu_irq_get(); with a
+ * fallback (amdgpu_dm_irq_set()) instead of amdgpu_irq_get(); with a
* NULL dc that fallback is a safe no-op.
*/
adev->mode_info.num_hpd = 0;
@@ -2247,7 +2247,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
/*
* num_hpd >= 1 makes irq_type (0) < num_hpd, so the loop takes the
* amdgpu_irq_get()/amdgpu_irq_put() branch instead of the
- * dc_interrupt_set() fallback. The mock device has irq.installed ==
+ * amdgpu_dm_irq_set() fallback. The mock device has irq.installed ==
* false, so both calls fail early with -ENOENT (logging an error)
* without touching the base-driver irq state.
*/
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
index b77df47d3095..a9c6485e2a9e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
@@ -642,31 +642,6 @@ static void dm_test_ism_init_sets_initial_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, ism->config.sso_num_frames, config.sso_num_frames);
}
-/* ===== Tests for amdgpu_dm_ism_fini ===== */
-
-/**
- * dm_test_ism_fini_after_init - fini cancels never-scheduled work without error
- * @test: KUnit test context
- */
-static void dm_test_ism_fini_after_init(struct kunit *test)
-{
- struct amdgpu_dm_ism *ism = alloc_test_ism(test);
- struct amdgpu_dm_ism_config config = {
- .filter_num_frames = 5,
- .filter_entry_count = 3,
- .activation_num_delay_frames = 10,
- .sso_num_frames = 2,
- };
-
- amdgpu_dm_ism_init(ism, &config);
- /* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
- amdgpu_dm_ism_fini(ism);
-
- /* FSM state is untouched by fini */
- KUNIT_EXPECT_EQ(test, (int)ism->current_state,
- (int)DM_ISM_STATE_FULL_POWER_RUNNING);
-}
-
/* ===== Tests for dm_ism_set_last_idle_ts ===== */
/**
@@ -897,6 +872,32 @@ static void register_test_acrtc(struct amdgpu_device *adev,
list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list);
}
+/* ===== Tests for amdgpu_dm_ism_flush ===== */
+
+/**
+ * dm_test_ism_flush_after_init - flush cancels never-scheduled work without error
+ * @test: KUnit test context
+ */
+static void dm_test_ism_flush_after_init(struct kunit *test)
+{
+ struct amdgpu_crtc *acrtc = alloc_test_acrtc(test, NULL);
+ struct amdgpu_dm_ism *ism = &acrtc->ism;
+ struct amdgpu_dm_ism_config config = {
+ .filter_num_frames = 5,
+ .filter_entry_count = 3,
+ .activation_num_delay_frames = 10,
+ .sso_num_frames = 2,
+ };
+
+ amdgpu_dm_ism_init(ism, &config);
+ /* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
+ amdgpu_dm_ism_flush(ism);
+
+ /* FSM state is untouched by flush */
+ KUNIT_EXPECT_EQ(test, (int)ism->current_state,
+ (int)DM_ISM_STATE_FULL_POWER_RUNNING);
+}
+
/* ===== Tests for amdgpu_dm_ism_commit_event ===== */
/**
@@ -922,7 +923,7 @@ static void dm_test_ism_commit_event_no_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -958,7 +959,7 @@ static void dm_test_ism_commit_event_cursor_transition(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -988,7 +989,7 @@ static void dm_test_ism_commit_event_invalid_event(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for amdgpu_dm_ism_force_full_power ===== */
@@ -1020,7 +1021,7 @@ static void dm_test_ism_force_full_power(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for amdgpu_dm_ism_disable / amdgpu_dm_ism_enable ===== */
@@ -1048,7 +1049,7 @@ static void dm_test_ism_disable_enable_cycle(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for dm_ism_dispatch_power_state (via commit_event) ===== */
@@ -1127,7 +1128,7 @@ static void dm_test_ism_dispatch_hysteresis_schedule_and_cancel(struct kunit *te
(int)DM_ISM_STATE_HYSTERESIS_BUSY);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1183,7 +1184,7 @@ static void dm_test_ism_dispatch_optimized_idle_defers_sso(struct kunit *test)
cancel_delayed_work(&acrtc->ism.sso_delayed_work);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/*
@@ -1285,7 +1286,7 @@ static void dm_test_ism_commit_allows_idle_on_optimized_idle(struct kunit *test)
cancel_delayed_work(&acrtc->ism.sso_delayed_work);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1322,7 +1323,7 @@ static void dm_test_ism_commit_enables_sso_on_optimized_idle_sso(struct kunit *t
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1371,7 +1372,7 @@ static void dm_test_ism_commit_disallows_idle_on_timer_aborted(struct kunit *tes
KUNIT_EXPECT_FALSE(test, adev->dm.dc->idle_optimizations_allowed);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1413,7 +1414,7 @@ static void dm_test_ism_exit_from_optimized_idle_disallows_idle(struct kunit *te
KUNIT_EXPECT_EQ(test, acrtc->ism.next_record_idx, 1);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1452,7 +1453,7 @@ static void dm_test_ism_exit_from_sso_disallows_idle(struct kunit *test)
KUNIT_EXPECT_EQ(test, acrtc->ism.next_record_idx, 1);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1496,7 +1497,7 @@ static void dm_test_ism_delayed_work_runs_timer_elapsed(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_ism_test_idle.calls, 1);
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1534,7 +1535,7 @@ static void dm_test_ism_sso_delayed_work_runs_sso_elapsed(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_ism_test_idle.calls, 3);
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
static struct kunit_case dm_ism_test_cases[] = {
@@ -1582,8 +1583,8 @@ static struct kunit_case dm_ism_test_cases[] = {
KUNIT_CASE(dm_test_ism_idle_delay_entry_count_exceeds_history_size),
/* amdgpu_dm_ism_init */
KUNIT_CASE(dm_test_ism_init_sets_initial_state),
- /* amdgpu_dm_ism_fini */
- KUNIT_CASE(dm_test_ism_fini_after_init),
+ /* amdgpu_dm_ism_flush */
+ KUNIT_CASE(dm_test_ism_flush_after_init),
/* dm_ism_set_last_idle_ts */
KUNIT_CASE(dm_test_ism_set_last_idle_ts_updates_timestamp),
/* dm_ism_insert_record */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 064af0022fb6..382eafab2d43 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -8,13 +8,16 @@
#include <kunit/test.h>
#include <drm/drm_drv.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_edid.h>
#include <drm/drm_fixed.h>
#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_mode_config.h>
#include <drm/drm_modeset_lock.h>
+#include <drm/drm_property.h>
#include <drm/display/drm_dp.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_dp_mst_helper.h>
@@ -28,6 +31,8 @@
#include "amdgpu_dm_hdcp.h"
#include "amdgpu_dm_mst_types.h"
#include "amdgpu_dm_kunit_test_helpers.h"
+#include "dsc/dsc.h"
+#include "inc/core_types.h"
#include "inc/link_service.h"
/*
@@ -886,6 +891,26 @@ static void dm_mst_test_aux_transfer_non_ack_reply(struct kunit *test)
}
/**
+ * dm_mst_test_aux_transfer_oversized - oversized AUX message is rejected.
+ * @test: KUnit test context.
+ *
+ * The payload is copied into a 16-byte stack buffer, so a larger message must
+ * be rejected with -E2BIG before the AUX handle is touched. The guard warns,
+ * which is the expected behaviour for this caller bug.
+ */
+static void dm_mst_test_aux_transfer_oversized(struct kunit *test)
+{
+ struct drm_dp_aux_msg msg = { 0 };
+ u8 buffer[17] = { 0 };
+
+ msg.request = DP_AUX_NATIVE_WRITE;
+ msg.buffer = buffer;
+ msg.size = sizeof(buffer);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer(NULL, &msg), (ssize_t)-E2BIG);
+}
+
+/**
* dm_mst_test_fill_payload_flags_native_write - native write request decode.
* @test: KUnit test context.
*
@@ -1277,6 +1302,203 @@ static void dm_mst_test_create_fake_mst_encoders(struct kunit *test)
}
}
+/* Tests for dm_dp_add_mst_connector */
+
+struct dm_mst_test_add_ctx {
+ struct amdgpu_device *adev;
+ struct amdgpu_dm_connector *master;
+ struct drm_dp_mst_port *port;
+ struct dc_link *link;
+};
+
+/*
+ * Stand in for amdgpu_display_modeset_create_props(), which the test module
+ * cannot link against. Only the properties amdgpu_dm_connector_init_helper()
+ * attaches are created.
+ */
+static void dm_mst_test_create_mode_props(struct kunit *test, struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct drm_device *drm = adev_to_drm(adev);
+
+ KUNIT_ASSERT_EQ(test, drm_mode_create_scaling_mode_property(drm), 0);
+
+ mode_info->underscan_property =
+ drm_property_create_range(drm, 0, "underscan", 0, 1);
+ mode_info->underscan_hborder_property =
+ drm_property_create_range(drm, 0, "underscan hborder", 0, 128);
+ mode_info->underscan_vborder_property =
+ drm_property_create_range(drm, 0, "underscan vborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_property);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_hborder_property);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_vborder_property);
+}
+
+/*
+ * Build the MST root connector and the topology port the new downstream
+ * connector hangs off. The port has no parent branch so the callback takes the
+ * "no branch descriptor" path without needing a sideband AUX backend.
+ */
+static void dm_mst_test_init_add_ctx(struct kunit *test, struct dm_mst_test_add_ctx *ctx)
+{
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ int ret;
+
+ adev = dm_kunit_alloc_adev(test);
+ drm = &adev->ddev;
+ ret = drmm_mode_config_init(drm);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ dm_mst_test_create_mode_props(test, adev);
+
+ adev->dm.adev = adev;
+ adev->dm.ddev = drm;
+ adev->dm.display_indexes_num = 2;
+ adev->mode_info.num_crtc = 2;
+ dm_dp_create_fake_mst_encoders(adev);
+
+ ctx->adev = adev;
+ ctx->link = dm_kunit_alloc_link(test);
+ /* Inflexible DIG mapping lets link_enc_cfg_get_link_enc() skip the dc lookup. */
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+
+ ctx->master = dm_kunit_alloc_connector(test, adev, ctx->link);
+ ctx->master->connector_id = 5;
+ ret = drm_connector_init(drm, &ctx->master->base, &dm_mst_test_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ctx->port = kunit_kzalloc(test, sizeof(*ctx->port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->port);
+ kref_init(&ctx->port->malloc_kref);
+ ctx->port->mgr = &ctx->master->mst_mgr;
+}
+
+/* True when @prop is attached to the connector's mode object. */
+static bool dm_mst_test_has_prop(struct drm_connector *connector, struct drm_property *prop)
+{
+ struct drm_object_properties *props = connector->base.properties;
+ int i;
+
+ if (!prop)
+ return false;
+
+ for (i = 0; i < props->count; i++)
+ if (props->properties[i] == prop)
+ return true;
+
+ return false;
+}
+
+/**
+ * dm_mst_test_add_mst_connector_creates - Test downstream connector creation
+ * @test: KUnit test context
+ *
+ * The topology callback must allocate a DisplayPort connector bound to the port
+ * and the root connector, inherit the root's dc_link and connector id, attach
+ * every fake MST encoder, publish the path property and take a malloc
+ * reference on the port.
+ */
+static void dm_mst_test_add_mst_connector_creates(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_connector *connector;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+
+ connector = dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-3");
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+
+ aconnector = to_amdgpu_dm_connector(connector);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->mst_output_port, ctx.port);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->mst_root, ctx.master);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->dc_link, ctx.link);
+ KUNIT_EXPECT_EQ(test, aconnector->connector_id, 5);
+ KUNIT_EXPECT_TRUE(test, aconnector->mst_status & MST_PROBE);
+ KUNIT_EXPECT_EQ(test, aconnector->branch_ieee_oui, 0U);
+ KUNIT_EXPECT_EQ(test, connector->connector_type, DRM_MODE_CONNECTOR_DisplayPort);
+ KUNIT_EXPECT_EQ(test, connector->possible_encoders, 0x3U);
+ KUNIT_EXPECT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_NOT_NULL(test, connector->path_blob_ptr);
+ KUNIT_EXPECT_EQ(test, kref_read(&ctx.port->malloc_kref), 2U);
+ KUNIT_EXPECT_TRUE(test,
+ dm_mst_test_has_prop(connector,
+ ctx.adev->ddev.mode_config.path_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_mst_test_has_prop(connector,
+ ctx.adev->ddev.mode_config.tile_property));
+
+ dm_dp_mst_connector_destroy(connector);
+}
+
+/**
+ * dm_mst_test_add_mst_connector_inherits_props - Test optional property sharing
+ * @test: KUnit test context
+ *
+ * Max bpc, VRR capable and colorspace properties are only attached to the new
+ * connector when the root connector already owns them, so the downstream
+ * connector shares the root's property objects.
+ */
+static void dm_mst_test_add_mst_connector_inherits_props(struct kunit *test)
+{
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_connector *connector;
+ struct drm_device *drm;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+ drm = &ctx.adev->ddev;
+
+ ctx.master->base.max_bpc_property =
+ drm_property_create_range(drm, 0, "max bpc", 8, 16);
+ ctx.master->base.vrr_capable_property =
+ drm_property_create_bool(drm, DRM_MODE_PROP_IMMUTABLE, "vrr_capable");
+ KUNIT_ASSERT_NOT_NULL(test, ctx.master->base.max_bpc_property);
+ KUNIT_ASSERT_NOT_NULL(test, ctx.master->base.vrr_capable_property);
+ KUNIT_ASSERT_EQ(test, drm_mode_create_dp_colorspace_property(&ctx.master->base, 0), 0);
+
+ connector = dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-4");
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+
+ KUNIT_EXPECT_PTR_EQ(test, connector->max_bpc_property, ctx.master->base.max_bpc_property);
+ KUNIT_EXPECT_PTR_EQ(test, connector->vrr_capable_property,
+ ctx.master->base.vrr_capable_property);
+ KUNIT_EXPECT_PTR_EQ(test, connector->colorspace_property,
+ ctx.master->base.colorspace_property);
+ KUNIT_EXPECT_TRUE(test, dm_mst_test_has_prop(connector, connector->max_bpc_property));
+ KUNIT_EXPECT_TRUE(test, dm_mst_test_has_prop(connector, connector->colorspace_property));
+
+ dm_dp_mst_connector_destroy(connector);
+}
+
+/**
+ * dm_mst_test_add_mst_connector_init_fails - Test the connector init failure path
+ * @test: KUnit test context
+ *
+ * Exhausting the device connector index space makes drm_connector_dynamic_init()
+ * fail, so the callback must free the connector it allocated, leave the port
+ * malloc reference untouched and report no connector to the MST helpers.
+ */
+static void dm_mst_test_add_mst_connector_init_fails(struct kunit *test)
+{
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_device *drm;
+ int id;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+ drm = &ctx.adev->ddev;
+
+ /* drm_connector_init_only() takes an index out of the same [0, 31] space. */
+ do {
+ id = ida_alloc_max(&drm->mode_config.connector_ida, 31, GFP_KERNEL);
+ } while (id >= 0);
+ KUNIT_ASSERT_EQ(test, id, -ENOSPC);
+
+ KUNIT_EXPECT_NULL(test, dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-5"));
+ KUNIT_EXPECT_EQ(test, kref_read(&ctx.port->malloc_kref), 1U);
+}
+
/**
* dm_mst_test_atomic_check_no_old_crtc - Test atomic check no-op path
* @test: KUnit test context
@@ -2058,20 +2280,1752 @@ static void dm_mst_test_sideband_msg_ready_ack_write_fails(struct kunit *test)
dm_mst_test_free_armed_sideband_connector(aconnector);
}
-#if !defined(CONFIG_DRM_AMD_DC_FP)
+/*
+ * Fake DPCD backing store for the DSC helpers. Unlike the sideband fake above
+ * it is addressed absolutely, because these helpers read offsets spread across
+ * the whole map (0x60 DSC caps, 0x100 link settings, 0x500 branch descriptor).
+ */
+#define DM_MST_TEST_DSC_DPCD_SIZE 0x600
+
+static u8 dm_mst_test_dsc_dpcd[DM_MST_TEST_DSC_DPCD_SIZE];
+static struct drm_dp_aux *dm_mst_test_dsc_aux_fail;
+
+static ssize_t dm_mst_test_dsc_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ size_t i;
+
+ if (aux == dm_mst_test_dsc_aux_fail)
+ return -EIO;
+
+ if (msg->address + msg->size > DM_MST_TEST_DSC_DPCD_SIZE)
+ return -EINVAL;
+
+ msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+
+ if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE)
+ return msg->size;
+
+ for (i = 0; i < msg->size; i++)
+ ((u8 *)msg->buffer)[i] = dm_mst_test_dsc_dpcd[msg->address + i];
+
+ return msg->size;
+}
+
+/* Clears the shared store; call once per test before initialising any AUX. */
+static void dm_mst_test_reset_dsc_dpcd(void)
+{
+ memset(dm_mst_test_dsc_dpcd, 0, sizeof(dm_mst_test_dsc_dpcd));
+ dm_mst_test_dsc_aux_fail = NULL;
+}
+
+static void dm_mst_test_init_dsc_aux(struct drm_dp_aux *aux, const char *name)
+{
+ aux->name = name;
+ aux->transfer = dm_mst_test_dsc_aux_transfer;
+ drm_dp_aux_init(aux);
+ drm_dp_dpcd_set_probe(aux, false);
+}
+
+static struct drm_dp_aux *dm_mst_test_alloc_dsc_aux(struct kunit *test, const char *name)
+{
+ struct drm_dp_aux *aux = kunit_kzalloc(test, sizeof(*aux), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, aux);
+ dm_mst_test_init_dsc_aux(aux, name);
+
+ return aux;
+}
+
+/* Tests for dp_get_link_current_set_bw */
+
+/*
+ * Program DPCD 0x100..0x10f, the 16-byte window the helper reads in one go.
+ * @coding is the raw DP_MAIN_LINK_CHANNEL_CODING_SET byte at 0x108.
+ */
+static void dm_mst_test_set_link_settings(u8 link_bw_set, u8 lane_count, u8 coding)
+{
+ dm_mst_test_dsc_dpcd[DP_LINK_BW_SET] = link_bw_set;
+ dm_mst_test_dsc_dpcd[DP_LANE_COUNT_SET] = lane_count;
+ dm_mst_test_dsc_dpcd[DP_MAIN_LINK_CHANNEL_CODING_SET] = coding;
+}
+
+struct dm_mst_link_bw_param {
+ const char *name;
+ u8 link_bw_set;
+ u8 lane_count;
+ u8 coding;
+ bool aux_fails;
+ bool supported;
+ uint32_t cur_link_bw;
+};
+
+static const struct dm_mst_link_bw_param dm_mst_link_bw_params[] = {
+ { "hbr2_8b_10b", DP_LINK_BW_5_4, 4, DP_8b_10b_ENCODING, false, true, 16761600 },
+ { "uhbr10", DP_LINK_BW_10, 4, DP_128b_132b_ENCODING, false, true, 38564000 },
+ { "uhbr13_5", DP_LINK_BW_13_5, 4, DP_128b_132b_ENCODING, false, true, 52061400 },
+ { "uhbr20", DP_LINK_BW_20, 4, DP_128b_132b_ENCODING, false, true, 77128000 },
+ { "unlisted_uhbr_rate", 0x1e, 4, DP_128b_132b_ENCODING, false, false, 0 },
+ { "unknown_encoding", DP_LINK_BW_5_4, 4, DP_UNKNOWN_ENCODING, false, false, 0 },
+ { "dpcd_read_error", DP_LINK_BW_5_4, 4, DP_8b_10b_ENCODING, true, false, 0 },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_link_bw, dm_mst_link_bw_params, name);
+
+/**
+ * dm_mst_test_link_current_set_bw - the current link settings are priced
+ * @test: KUnit test context
+ *
+ * For 8b/10b the raw DP_LINK_BW_SET byte is the link rate in 27MHz units, so
+ * HBR2 (0x14) yields 20 * 27000 * 10 kbps per lane scaled by the 80% data
+ * efficiency and the 97% FEC efficiency. For 128b/132b the byte instead
+ * selects a UHBR rate scaled by its own efficiency. An unlisted UHBR rate, an
+ * unknown channel coding and a short DPCD read all report no bandwidth.
+ */
+static void dm_mst_test_link_current_set_bw(struct kunit *test)
+{
+ const struct dm_mst_link_bw_param *param = test->param_value;
+ uint32_t cur_link_bw = 0xdeadbeef;
+ struct drm_dp_aux *aux;
+
+ dm_mst_test_reset_dsc_dpcd();
+ aux = dm_mst_test_alloc_dsc_aux(test, "dm_mst_test_link_bw_aux");
+ dm_mst_test_set_link_settings(param->link_bw_set, param->lane_count, param->coding);
+ if (param->aux_fails)
+ dm_mst_test_dsc_aux_fail = aux;
+
+ KUNIT_EXPECT_EQ(test, dp_get_link_current_set_bw(aux, &cur_link_bw), param->supported);
+ KUNIT_EXPECT_EQ(test, cur_link_bw, param->cur_link_bw);
+}
+
+/* Tests for is_synaptics_cascaded_panamera */
+
+/*
+ * A Panamera hub is identified by its branch device ID plus the high nibble of
+ * the fifth branch device name byte; the cascaded variant additionally reports
+ * SYNAPTICS_CASCADED_HUB_ID at DPCD 0x50e.
+ */
+static void dm_mst_test_set_panamera_ids(struct dc_link *link, u32 branch_dev_id,
+ u8 dev_name_4, u8 cascaded_id)
+{
+ link->dpcd_caps.branch_dev_id = branch_dev_id;
+ link->dpcd_caps.branch_dev_name[4] = dev_name_4;
+ dm_mst_test_dsc_dpcd[DP_BRANCH_VENDOR_SPECIFIC_START + 2] = cascaded_id;
+}
+
+static struct drm_dp_mst_port *dm_mst_test_alloc_mgr_port(struct kunit *test)
+{
+ struct drm_dp_mst_topology_mgr *mgr;
+ struct drm_dp_mst_port *port;
+
+ mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mgr);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+
+ mutex_init(&mgr->lock);
+ mgr->aux = dm_mst_test_alloc_dsc_aux(test, "dm_mst_test_mgr_aux");
+ port->mgr = mgr;
+
+ return port;
+}
+
+struct dm_mst_panamera_param {
+ const char *name;
+ u32 branch_dev_id;
+ u8 dev_name_4;
+ u8 cascaded_id;
+ bool aux_fails;
+ bool cascaded;
+};
+
+static const struct dm_mst_panamera_param dm_mst_panamera_params[] = {
+ { "cascaded_hub", DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID, false, true },
+ { "wrong_dev_id", 0x001122, 0x50, SYNAPTICS_CASCADED_HUB_ID, false, false },
+ { "not_panamera", DP_BRANCH_DEVICE_ID_90CC24, 0x40,
+ SYNAPTICS_CASCADED_HUB_ID, false, false },
+ { "not_cascaded", DP_BRANCH_DEVICE_ID_90CC24, 0x50, 0, false, false },
+ { "dpcd_read_error", DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID, true, false },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_panamera, dm_mst_panamera_params, name);
+
+/**
+ * dm_mst_test_synaptics_cascaded - only a cascaded Panamera hub is detected
+ * @test: KUnit test context
+ *
+ * All three conditions must hold: the Synaptics branch device ID, a Panamera
+ * device name and the cascaded hub ID in the branch vendor data. A failed
+ * vendor read leaves the hub undetected.
+ */
+static void dm_mst_test_synaptics_cascaded(struct kunit *test)
+{
+ const struct dm_mst_panamera_param *param = test->param_value;
+ struct drm_dp_mst_port *port;
+ struct dc_link *link;
+
+ dm_mst_test_reset_dsc_dpcd();
+ port = dm_mst_test_alloc_mgr_port(test);
+ link = dm_kunit_alloc_link(test);
+ dm_mst_test_set_panamera_ids(link, param->branch_dev_id, param->dev_name_4,
+ param->cascaded_id);
+ if (param->aux_fails)
+ dm_mst_test_dsc_aux_fail = port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, is_synaptics_cascaded_panamera(link, port), param->cascaded);
+}
+
+/* Tests for validate_dsc_caps_on_connector */
+
+struct dm_mst_test_dsc_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_dm_connector *root;
+ struct drm_dp_mst_port *port;
+ struct dc_sink *sink;
+ struct dc_link *link;
+};
+
+/*
+ * Build an MST endpoint whose port hangs directly off the primary branch. With
+ * an all-zero DPCD, drm_dp_mst_dsc_aux_for_port() finds no DSC-capable AUX, so
+ * each test can steer the driver's own fallbacks in isolation.
+ */
+static void dm_mst_test_init_dsc_ctx(struct kunit *test, struct dm_mst_test_dsc_ctx *ctx)
+{
+ struct drm_dp_mst_branch *branch;
+ struct dc *dc;
+
+ dm_mst_test_reset_dsc_dpcd();
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ ctx->root = kunit_kzalloc(test, sizeof(*ctx->root), GFP_KERNEL);
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ branch = kunit_kzalloc(test, sizeof(*branch), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->root);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ KUNIT_ASSERT_NOT_NULL(test, branch);
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->ctx = dc->ctx;
+
+ ctx->port = dm_mst_test_alloc_mgr_port(test);
+ ctx->port->parent = branch;
+ dm_mst_test_init_dsc_aux(&ctx->port->aux, "dm_mst_test_port_dsc_aux");
+ dm_mst_test_init_dsc_aux(&ctx->root->dm_dp_aux.aux, "dm_mst_test_root_dsc_aux");
+
+ ctx->aconnector->dc_link = ctx->link;
+ ctx->aconnector->dc_sink = ctx->sink;
+ ctx->aconnector->mst_output_port = ctx->port;
+ ctx->aconnector->mst_root = ctx->root;
+}
+
+/* Make needs_dsc_aux_workaround() accept the link. */
+static void dm_mst_test_arm_dsc_aux_workaround(struct dc_link *link)
+{
+ link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
+ link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
+ link->dpcd_caps.sink_count.bits.SINK_COUNT = 2;
+}
+
/**
- * dm_mst_test_fp_guarded_public_stubs - Test FP-off public fallbacks
+ * dm_mst_test_validate_dsc_caps_no_aux - no DSC AUX means no DSC capabilities
* @test: KUnit test context
*
- * When CONFIG_DRM_AMD_DC_FP is disabled, the public DSC validation helper
- * has no FP body and must return DC_OK without touching its arguments.
+ * When neither the DRM helper, the Synaptics workaround nor the cascaded hub
+ * quirk yields a DSC AUX channel, validation must fail without touching DPCD.
*/
-static void dm_mst_test_fp_guarded_public_stubs(struct kunit *test)
+static void dm_mst_test_validate_dsc_caps_no_aux(struct kunit *test)
{
- KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(NULL, NULL),
- (enum dc_status)DC_OK);
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_NULL(test, ctx.aconnector->dsc_aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_aux_workaround - MST dock AUX fallback is used
+ * @test: KUnit test context
+ *
+ * A DSC capable dock in front of a non-DSC display leaves the DRM helper
+ * without an AUX, so the driver must fall back to the MST root's AUX and parse
+ * the DSC capabilities read from it.
+ */
+static void dm_mst_test_validate_dsc_caps_aux_workaround(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_dsc_dpcd[DP_DSC_SUPPORT] = DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+
+ KUNIT_EXPECT_TRUE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, &ctx.root->dm_dp_aux.aux);
+ KUNIT_EXPECT_TRUE(test, ctx.sink->dsc_caps.dsc_dec_caps.is_dsc_supported);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_cascaded_hub - cascaded hub uses the mgr AUX
+ * @test: KUnit test context
+ *
+ * On a cascaded Synaptics Panamera hub the DSC decoder lives on the primary
+ * branch, so the topology manager's AUX must win over every other fallback.
+ */
+static void dm_mst_test_validate_dsc_caps_cascaded_hub(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_set_panamera_ids(ctx.link, DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID);
+ dm_mst_test_dsc_dpcd[DP_DSC_SUPPORT] = DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+
+ KUNIT_EXPECT_TRUE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, ctx.port->mgr->aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_read_error - a failed DSC caps read is fatal
+ * @test: KUnit test context
+ */
+static void dm_mst_test_validate_dsc_caps_read_error(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_dsc_aux_fail = &ctx.root->dm_dp_aux.aux;
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, &ctx.root->dm_dp_aux.aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_unsupported - a sink without DSC is rejected
+ * @test: KUnit test context
+ *
+ * The AUX resolves but the sink reports no decompression support, so parsing
+ * the raw capabilities fails and the connector must not be marked DSC capable.
+ */
+static void dm_mst_test_validate_dsc_caps_unsupported(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_FALSE(test, ctx.sink->dsc_caps.dsc_dec_caps.is_dsc_supported);
+}
+
+/* Tests for dm_dp_mst_is_port_support_mode */
+
+static uint32_t dm_mst_test_root_link_bw_kbps;
+
+static uint32_t dm_mst_test_root_bandwidth_kbps(const struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ return dm_mst_test_root_link_bw_kbps;
+}
+
+struct dm_mst_test_port_mode_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_stream_state *stream;
+ struct drm_dp_mst_port *port;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct dc *dc;
+};
+
+/*
+ * Build the minimum needed to price a mode: a link whose root bandwidth is
+ * faked, a virtual channel sized by the port's full_pbn, and a 24bpp timing
+ * that needs pix_clk_100hz / 10 * 24 kbps uncompressed.
+ */
+static void dm_mst_test_init_port_mode_ctx(struct kunit *test,
+ struct dm_mst_test_port_mode_ctx *ctx,
+ uint32_t root_link_bw_kbps, u32 full_pbn,
+ uint32_t pix_clk_100hz)
+{
+ struct link_service *link_srv;
+ struct resource_pool *res_pool;
+
+ dm_mst_test_reset_dsc_dpcd();
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+
+ dm_mst_test_root_link_bw_kbps = root_link_bw_kbps;
+ link_srv->dp_link_bandwidth_kbps = dm_mst_test_root_bandwidth_kbps;
+
+ ctx->dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->dc->link_srv = link_srv;
+ ctx->dc->res_pool = res_pool;
+
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->dc = ctx->dc;
+ ctx->link->ctx = ctx->dc->ctx;
+
+ ctx->sink->ctx = ctx->dc->ctx;
+ ctx->port = dm_mst_test_alloc_mgr_port(test);
+ ctx->port->full_pbn = full_pbn;
+
+ ctx->stream = dm_kunit_alloc_stream(test, ctx->link);
+ ctx->stream->sink = ctx->sink;
+ ctx->stream->timing.display_color_depth = COLOR_DEPTH_888;
+ ctx->stream->timing.pix_clk_100hz = pix_clk_100hz;
+
+ ctx->aconnector->dc_link = ctx->link;
+ ctx->aconnector->dc_sink = ctx->sink;
+ ctx->aconnector->mst_output_port = ctx->port;
+}
+
+/**
+ * dm_mst_test_port_mode_fits_without_dsc - sufficient bandwidth needs no DSC
+ * @test: KUnit test context
+ *
+ * When the uncompressed stream fits into the smaller of the root link and the
+ * virtual channel bandwidth, the mode is accepted before any DSC evaluation.
+ */
+static void dm_mst_test_port_mode_fits_without_dsc(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 1000000, 1000, 100000);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_port_mode_no_dsc_aux - DSC is required but unavailable
+ * @test: KUnit test context
+ *
+ * A mode that exceeds the end-to-end bandwidth on a connector without a DSC
+ * AUX channel cannot be compressed, so validation must fail.
+ */
+static void dm_mst_test_port_mode_no_dsc_aux(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 100000, 10, 100000);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/**
+ * dm_mst_test_port_mode_no_common_dsc_config - no shared DSC config is fatal
+ * @test: KUnit test context
+ *
+ * With a DSC AUX but no DSC encoder in the resource pool, source and sink share
+ * no usable DSC configuration and the mode must be rejected.
+ */
+static void dm_mst_test_port_mode_no_common_dsc_config(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 100000, 10, 100000);
+ ctx.aconnector->dsc_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/*
+ * 1920x1080@60 RGB 8bpc needs 3564000 kbps uncompressed, and roughly 1188000
+ * kbps at the 8bpp DSC policy minimum.
+ */
+#define DM_MST_TEST_DSC_PIX_CLK_100HZ 1485000
+
+/* Enough of dsc2_get_enc_caps() for the DSC policy and bandwidth maths. */
+static void dm_mst_test_dsc_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz)
+{
+ dsc_enc_caps->dsc_version = 0x21;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1;
+ dsc_enc_caps->lb_bit_depth = 13;
+ dsc_enc_caps->is_block_pred_supported = true;
+ dsc_enc_caps->color_formats.bits.RGB = 1;
+ dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
+ dsc_enc_caps->max_total_throughput_mps = 4800;
+ dsc_enc_caps->max_slice_width = 5184;
+ dsc_enc_caps->bpp_increment_div = 16;
+}
+
+static const struct dsc_funcs dm_mst_test_dsc_funcs = {
+ .dsc_get_enc_caps = dm_mst_test_dsc_get_enc_caps,
+};
+
+/* Install the DSC encoder fake and matching sink decoder capabilities. */
+static void dm_mst_test_setup_dsc_caps(struct kunit *test, struct dc *dc, struct dc_sink *sink)
+{
+ struct dsc_dec_dpcd_caps *dec = &sink->dsc_caps.dsc_dec_caps;
+ struct display_stream_compressor *dsc;
+
+ dsc = kunit_kzalloc(test, sizeof(*dsc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dsc);
+
+ dsc->funcs = &dm_mst_test_dsc_funcs;
+ dsc->ctx = dc->ctx;
+ dc->res_pool->dscs[0] = dsc;
+
+ dec->is_dsc_supported = true;
+ dec->dsc_version = 0x21;
+ dec->rc_buffer_size = 16 * 1024;
+ dec->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dec->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dec->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dec->lb_bit_depth = 13;
+ dec->is_block_pred_supported = true;
+ dec->color_formats.bits.RGB = 1;
+ dec->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
+ dec->throughput_mode_0_mps = 1000;
+ dec->throughput_mode_1_mps = 1000;
+ dec->max_slice_width = 5120;
+ dec->bpp_increment_div = 16;
+}
+
+static void dm_mst_test_set_dsc_timing(struct dc_crtc_timing *timing)
+{
+ timing->display_color_depth = COLOR_DEPTH_888;
+ timing->pixel_encoding = PIXEL_ENCODING_RGB;
+ timing->h_addressable = 1920;
+ timing->v_addressable = 1080;
+ timing->pix_clk_100hz = DM_MST_TEST_DSC_PIX_CLK_100HZ;
+}
+
+/*
+ * Give the source a DSC encoder and the sink matching decoder capabilities so
+ * is_dsc_common_config_possible() succeeds, and switch to a timing that does
+ * not fit uncompressed.
+ */
+static void dm_mst_test_enable_dsc(struct kunit *test, struct dm_mst_test_port_mode_ctx *ctx)
+{
+ struct drm_dp_mst_branch *branch;
+
+ branch = kunit_kzalloc(test, sizeof(*branch), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, branch);
+
+ dm_mst_test_setup_dsc_caps(test, ctx->dc, ctx->sink);
+ dm_mst_test_set_dsc_timing(&ctx->stream->timing);
+
+ ctx->port->parent = branch;
+ dm_mst_test_init_dsc_aux(&ctx->port->aux, "dm_mst_test_port_mode_aux");
+ ctx->aconnector->dsc_aux = ctx->port->mgr->aux;
+}
+
+/**
+ * dm_mst_test_port_mode_dsc_passthrough_fits - DSC passthrough accepts the mode
+ * @test: KUnit test context
+ *
+ * With DSC passthrough the compressed stream travels the whole path, so a
+ * minimum compression that fits the end-to-end bandwidth enables DSC.
+ */
+static void dm_mst_test_port_mode_dsc_passthrough_fits(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_port_mode_dsc_passthrough_too_narrow - max compression still too big
+ * @test: KUnit test context
+ *
+ * When even the smallest DSC bitstream exceeds the end-to-end bandwidth the
+ * mode must be rejected instead of enabling DSC.
+ */
+static void dm_mst_test_port_mode_dsc_passthrough_too_narrow(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 1000000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_too_slow - the uncompressed last link is checked
+ * @test: KUnit test context
+ *
+ * DSC is decoded at the endpoint, so the last DP link still carries the
+ * uncompressed stream. Its current link settings are read from DPCD and cached
+ * on the connector, and a mode that does not fit is rejected.
+ */
+static void dm_mst_test_port_mode_last_link_too_slow(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ /* RBR x1: 1257120 kbps, far below the 3564000 kbps the mode needs. */
+ dm_mst_test_set_link_settings(DP_LINK_BW_1_62, 1, DP_8b_10b_ENCODING);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->mst_local_bw, 1257120U);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->vc_full_pbn, ctx.port->full_pbn);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_cached_bw - a cached last link bandwidth is reused
+ * @test: KUnit test context
+ *
+ * While the virtual channel allocation is unchanged the previously read link
+ * bandwidth is reused instead of going out to DPCD again.
+ */
+static void dm_mst_test_port_mode_last_link_cached_bw(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ ctx.aconnector->vc_full_pbn = ctx.port->full_pbn;
+ ctx.aconnector->mst_local_bw = 100000;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->mst_local_bw, 100000U);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_synaptics_quirk - Synaptics hubs skip the check
+ * @test: KUnit test context
+ *
+ * Synaptics branch devices misreport their last link settings, so the last
+ * link bandwidth check is skipped for them and the mode is accepted.
+ */
+static void dm_mst_test_port_mode_last_link_synaptics_quirk(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ ctx.aconnector->branch_ieee_oui = DP_BRANCH_DEVICE_ID_90CC24;
+ dm_mst_test_set_link_settings(DP_LINK_BW_1_62, 1, DP_8b_10b_ENCODING);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_port_mode_upstream_vc_too_small - the upstream hop is the bottleneck
+ * @test: KUnit test context
+ *
+ * For a nested topology the virtual channel of the link before the last one
+ * caps the compressed bandwidth, and a mode that exceeds it is rejected.
+ */
+static void dm_mst_test_port_mode_upstream_vc_too_small(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+ struct drm_dp_mst_port *upstream;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_NONE;
+
+ upstream = kunit_kzalloc(test, sizeof(*upstream), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, upstream);
+ /* 100 PBN is about 670950 kbps, below the DSC minimum for this mode. */
+ upstream->full_pbn = 100;
+ ctx.port->parent->port_parent = upstream;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/**
+ * dm_mst_test_port_mode_branch_throughput_exceeded - branch decoder limit applies
+ * @test: KUnit test context
+ *
+ * Even with a valid DSC configuration the branch decoder's overall throughput
+ * for RGB must be able to carry the pixel rate.
+ */
+static void dm_mst_test_port_mode_branch_throughput_exceeded(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+ /* 100 Mpix/s cannot carry the 148.5 Mpix/s this mode needs. */
+ ctx.sink->dsc_caps.dsc_dec_caps.branch_overall_throughput_0_mps = 100;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/* Tests for get_conv_frl_bw */
+
+/* Deterministic stand-in for the DC raw-FRL-rate lookup table. */
+static uint32_t dm_mst_test_bw_kbps_from_raw_frl(uint8_t bw)
+{
+ return bw * 3000;
+}
+
+/*
+ * Wire up a DP-to-HDMI2.1 protocol converter: the PCON capability lives on the
+ * DC caps, the converter's own limit in the downstream port caps, and the sink
+ * limits in the EDID caps.
+ */
+static struct amdgpu_dm_connector *dm_mst_test_alloc_frl_connector(struct kunit *test,
+ bool pcon_support,
+ u8 dwn_strm_port_type,
+ u8 max_encoded_link_bw,
+ u8 max_frl_rate,
+ u8 frl_dsc_max_frl_rate)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct link_service *link_srv;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct dc *dc;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+
+ link_srv->bw_kbps_from_raw_frl_link_rate_data = dm_mst_test_bw_kbps_from_raw_frl;
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->link_srv = link_srv;
+ dc->caps.dp_hdmi21_pcon_support = pcon_support;
+
+ link = dm_kunit_alloc_link(test);
+ link->dc = dc;
+
+ sink->edid_caps.max_frl_rate = max_frl_rate;
+ sink->edid_caps.frl_dsc_max_frl_rate = frl_dsc_max_frl_rate;
+
+ aconnector->dc_link = link;
+ aconnector->dc_sink = sink;
+ aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE =
+ dwn_strm_port_type;
+ aconnector->mst_downstream_port_caps.bytes.byte2.bits.MAX_ENCODED_LINK_BW_SUPPORT =
+ max_encoded_link_bw;
+
+ return aconnector;
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_no_pcon_support - DC without PCON support finds no FRL
+ * @test: KUnit test context
+ */
+static void dm_mst_test_conv_frl_bw_no_pcon_support(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, false, DOWN_STREAM_DETAILED_HDMI,
+ 3, 5, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+ KUNIT_EXPECT_EQ(test, dsc_bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_not_hdmi_port - a non-HDMI downstream port has no FRL
+ * @test: KUnit test context
+ */
+static void dm_mst_test_conv_frl_bw_not_hdmi_port(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_DP, 3, 5, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_sink_without_frl - a sink not reporting FRL is skipped
+ * @test: KUnit test context
+ *
+ * Without a sink FRL rate in the EDID there is no endpoint to negotiate with,
+ * so no bandwidth is reported even though the converter advertises one.
+ */
+static void dm_mst_test_conv_frl_bw_sink_without_frl(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_HDMI,
+ 3, 0, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_bottleneck - the converter and sink limits are combined
+ * @test: KUnit test context
+ *
+ * The reported bandwidth is the smaller of the converter and sink FRL rates,
+ * and the DSC bandwidth is further capped by the sink's DSC FRL rate.
+ */
+static void dm_mst_test_conv_frl_bw_bottleneck(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_HDMI,
+ 3, 5, 2);
+
+ KUNIT_EXPECT_TRUE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 9000U);
+ KUNIT_EXPECT_EQ(test, dsc_bw_in_kbps, 6000U);
+}
+
+/* Tests for log_dsc_params */
+
+/**
+ * dm_mst_test_log_dsc_params - logging the fairness vars leaves them untouched
+ * @test: KUnit test context
+ *
+ * log_dsc_params() only traces, so the only observable contract is that it
+ * walks @count entries starting at @k without modifying them.
+ */
+static void dm_mst_test_log_dsc_params(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[3] = {
+ { .pbn = 100, .dsc_enabled = false, .bpp_x16 = 160 },
+ { .pbn = 200, .dsc_enabled = true, .bpp_x16 = 192 },
+ { .pbn = 300, .dsc_enabled = true, .bpp_x16 = 256 },
+ };
+
+ log_dsc_params(2, vars, 1);
+
+ KUNIT_EXPECT_EQ(test, vars[1].pbn, 200);
+ KUNIT_EXPECT_EQ(test, vars[2].bpp_x16, 256);
+}
+
+/* Tests for find_crtc_index_in_state_by_stream and is_dsc_precompute_needed */
+
+struct dm_mst_test_crtc_state_ctx {
+ struct drm_atomic_commit *state;
+ struct drm_crtc *crtcs;
+ struct dm_crtc_state *crtc_states;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+};
+
+/*
+ * Hand-build an atomic state with @num_crtc CRTCs, each carrying a DM CRTC
+ * state. drm_atomic_state_alloc() would need a fully registered mode config,
+ * and the helpers under test only walk the crtcs/connectors arrays.
+ */
+static void dm_mst_test_init_crtc_state_ctx(struct kunit *test,
+ struct dm_mst_test_crtc_state_ctx *ctx,
+ unsigned int num_crtc)
+{
+ struct amdgpu_device *adev;
+ unsigned int i;
+
+ adev = dm_kunit_alloc_adev(test);
+ adev->ddev.mode_config.num_crtc = num_crtc;
+
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ ctx->crtcs = kunit_kcalloc(test, num_crtc, sizeof(*ctx->crtcs), GFP_KERNEL);
+ ctx->crtc_states = kunit_kcalloc(test, num_crtc, sizeof(*ctx->crtc_states), GFP_KERNEL);
+ ctx->connector = kunit_kzalloc(test, sizeof(*ctx->connector), GFP_KERNEL);
+ ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_states);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->connector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+
+ ctx->state->dev = &adev->ddev;
+ ctx->state->crtcs = kunit_kcalloc(test, num_crtc, sizeof(*ctx->state->crtcs), GFP_KERNEL);
+ ctx->state->connectors = kunit_kzalloc(test, sizeof(*ctx->state->connectors), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->connectors);
+
+ for (i = 0; i < num_crtc; i++) {
+ ctx->crtcs[i].dev = &adev->ddev;
+ ctx->crtc_states[i].base.crtc = &ctx->crtcs[i];
+ ctx->state->crtcs[i].ptr = &ctx->crtcs[i];
+ ctx->state->crtcs[i].new_state = &ctx->crtc_states[i].base;
+ ctx->state->crtcs[i].old_state = &ctx->crtc_states[i].base;
+ }
+}
+
+/* Attach the context's connector to @crtc so the CRTC looks driven. */
+static void dm_mst_test_attach_connector(struct dm_mst_test_crtc_state_ctx *ctx,
+ struct drm_crtc *crtc)
+{
+ ctx->conn_state->crtc = crtc;
+ ctx->state->connectors[0].ptr = ctx->connector;
+ ctx->state->connectors[0].new_state = ctx->conn_state;
+ ctx->state->num_connector = 1;
+}
+
+/**
+ * dm_mst_test_find_crtc_index_matches - the CRTC driving a stream is found
+ * @test: KUnit test context
+ */
+static void dm_mst_test_find_crtc_index_matches(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 3);
+ stream = dm_kunit_alloc_stream(test, NULL);
+ ctx.crtc_states[2].stream = stream;
+
+ KUNIT_EXPECT_EQ(test, find_crtc_index_in_state_by_stream(ctx.state, stream), 2);
+}
+
+/**
+ * dm_mst_test_find_crtc_index_no_match - an unknown stream yields -1
+ * @test: KUnit test context
+ */
+static void dm_mst_test_find_crtc_index_no_match(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 2);
+ stream = dm_kunit_alloc_stream(test, NULL);
+
+ KUNIT_EXPECT_EQ(test, find_crtc_index_in_state_by_stream(ctx.state, stream), -1);
+}
+
+struct dm_mst_precompute_param {
+ const char *name;
+ bool connector_attached;
+ bool has_stream;
+ enum dc_connection_type link_type;
+ bool dsc_support;
+ bool dsc_passthrough;
+ bool needed;
+};
+
+static const struct dm_mst_precompute_param dm_mst_precompute_params[] = {
+ { "no_connector", false, true, dc_connection_mst_branch, true, false, false },
+ { "dsc_hub", true, true, dc_connection_mst_branch, true, false, true },
+ { "dsc_passthrough_hub", true, true, dc_connection_mst_branch, false, true, true },
+ { "sst_link", true, true, dc_connection_single, true, false, false },
+ { "mst_without_dsc", true, true, dc_connection_mst_branch, false, false, false },
+ { "no_stream", true, false, dc_connection_mst_branch, true, false, false },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_precompute, dm_mst_precompute_params, name);
+
+/**
+ * dm_mst_test_dsc_precompute_needed - precompute needs a driven DSC MST hub
+ * @test: KUnit test context
+ *
+ * A DSC or DSC passthrough capable MST branch that a connector in the state
+ * drives needs its bandwidth precomputed. A CRTC no connector drives aborts
+ * the scan, and SST links or MST branches without DSC never need it.
+ */
+static void dm_mst_test_dsc_precompute_needed(struct kunit *test)
+{
+ const struct dm_mst_precompute_param *param = test->param_value;
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_link *link;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 1);
+ if (param->connector_attached)
+ dm_mst_test_attach_connector(&ctx, &ctx.crtcs[0]);
+
+ if (param->has_stream) {
+ link = dm_kunit_alloc_link(test);
+ link->type = param->link_type;
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT =
+ param->dsc_support;
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT =
+ param->dsc_passthrough;
+ ctx.crtc_states[0].stream = dm_kunit_alloc_stream(test, link);
+ }
+
+ KUNIT_EXPECT_EQ(test, is_dsc_precompute_needed(ctx.state), param->needed);
+}
+
+/* Tests for is_dsc_need_re_compute */
+
+struct dm_mst_test_recompute_ctx {
+ struct amdgpu_device *adev;
+ struct drm_atomic_commit *state;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct dc_state *dc_state;
+ struct dc_link *link;
+ struct dc *dc;
+};
+
+/*
+ * One MST connector on one CRTC, with an empty new dc_state and an empty
+ * current dc_state. Tests populate the streams they need and adjust the CRTC
+ * state flags to select the branch under test.
+ */
+static void dm_mst_test_init_recompute_ctx(struct kunit *test,
+ struct dm_mst_test_recompute_ctx *ctx)
+{
+ struct drm_crtc *crtc;
+
+ ctx->adev = dm_kunit_alloc_adev(test);
+ ctx->adev->ddev.mode_config.num_crtc = 1;
+
+ ctx->dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->dc->current_state = dm_kunit_alloc_dc_state(test);
+ ctx->dc_state = dm_kunit_alloc_dc_state(test);
+
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->dc = ctx->dc;
+ ctx->link->type = dc_connection_mst_branch;
+
+ ctx->aconnector = dm_kunit_alloc_connector(test, ctx->adev, ctx->link);
+ ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
+ crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+
+ ctx->state->dev = &ctx->adev->ddev;
+ ctx->state->crtcs = kunit_kzalloc(test, sizeof(*ctx->state->crtcs), GFP_KERNEL);
+ ctx->state->connectors = kunit_kzalloc(test, sizeof(*ctx->state->connectors), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->connectors);
+
+ crtc->dev = &ctx->adev->ddev;
+ ctx->crtc_state->crtc = crtc;
+ ctx->state->crtcs[0].ptr = crtc;
+ ctx->state->crtcs[0].new_state = ctx->crtc_state;
+ ctx->state->crtcs[0].old_state = ctx->crtc_state;
+
+ ctx->conn_state->connector = &ctx->aconnector->base;
+ ctx->conn_state->crtc = crtc;
+ ctx->state->connectors[0].ptr = &ctx->aconnector->base;
+ ctx->state->connectors[0].new_state = ctx->conn_state;
+ ctx->state->num_connector = 1;
+}
+
+static struct dc_stream_state *dm_mst_test_add_link_stream(struct kunit *test,
+ struct dc_state *dc_state,
+ struct dc_link *link,
+ struct amdgpu_dm_connector *aconnector)
+{
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, link);
+
+ KUNIT_ASSERT_LT(test, dc_state->stream_count, MAX_PIPES);
+ stream->dm_stream_context = aconnector;
+ dc_state->streams[dc_state->stream_count++] = stream;
+
+ return stream;
+}
+
+/**
+ * dm_mst_test_recompute_not_mst_branch - only MST branches are recomputed
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_not_mst_branch(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_legacy_hub_without_dsc - old hubs without DSC are skipped
+ * @test: KUnit test context
+ *
+ * A hub matching the no-virtual-DPCD workaround but reporting neither DSC nor
+ * DSC passthrough support cannot use MST DSC at all.
+ */
+static void dm_mst_test_recompute_legacy_hub_without_dsc(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_no_stream_on_link - no stream on the link, nothing to do
+ * @test: KUnit test context
+ *
+ * The new state only drives another link, so this hub keeps its current DSC
+ * configuration.
+ */
+static void dm_mst_test_recompute_no_stream_on_link(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dc_link *other_link;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ other_link = dm_kunit_alloc_link(test);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, other_link, ctx.aconnector);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_on_mode_change - a modeset on the link forces a recompute
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_on_mode_change(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+ ctx.crtc_state->mode_changed = true;
+
+ KUNIT_EXPECT_TRUE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_unchanged_stream - an untouched stream needs no recompute
+ * @test: KUnit test context
+ *
+ * The same stream is present in both the new and the current state and its
+ * CRTC reports no change, so the existing DSC configuration still applies.
+ */
+static void dm_mst_test_recompute_unchanged_stream(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, ctx.aconnector);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_stream_removed - dropping a stream forces a recompute
+ * @test: KUnit test context
+ *
+ * A stream that is on the link in the current state but absent from the new
+ * state frees up bandwidth, so the remaining streams must be recomputed.
+ */
+static void dm_mst_test_recompute_stream_removed(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct amdgpu_dm_connector *gone;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ gone = dm_kunit_alloc_connector(test, ctx.adev, ctx.link);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, gone);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+
+ KUNIT_EXPECT_TRUE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_stream_without_connector - streams need a DM connector
+ * @test: KUnit test context
+ *
+ * A stream on the link whose DM context is not set cannot be attributed to a
+ * connector, so it does not count towards the streams on the link.
+ */
+static void dm_mst_test_recompute_stream_without_connector(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, NULL);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_connector_without_crtc - a disabled connector is skipped
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_connector_without_crtc(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, ctx.aconnector);
+ ctx.conn_state->crtc = NULL;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/* Tests for compute_mst_dsc_configs_for_state and pre_validate_dsc */
+
+typedef enum dc_status (*dm_mst_test_remove_stream_fn)(struct dc *dc, struct dc_state *new_ctx,
+ struct dc_stream_state *stream);
+
+static enum dc_status dm_mst_test_remove_stream_fails(struct dc *dc, struct dc_state *new_ctx,
+ struct dc_stream_state *stream)
+{
+ return DC_ERROR_UNEXPECTED;
+}
+
+/*
+ * Add a stream to @ctx that walks as far into the DSC config helpers as the
+ * caller allows: an MST signal, a DM connector, an MST output port and a DSC
+ * capable sink. The helpers dereference res_pool->funcs unconditionally, so
+ * the pool is always given one, carrying @remove_stream.
+ */
+static struct dc_stream_state *
+dm_mst_test_add_mst_dsc_stream(struct kunit *test, struct dm_mst_test_recompute_ctx *ctx,
+ dm_mst_test_remove_stream_fn remove_stream)
+{
+ struct dc_stream_state *stream;
+ struct resource_pool *res_pool;
+ struct drm_dp_mst_port *port;
+ struct resource_funcs *funcs;
+ struct dc_sink *sink;
+
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, funcs);
+
+ funcs->remove_stream_from_ctx = remove_stream;
+ res_pool->funcs = funcs;
+ ctx->dc->res_pool = res_pool;
+ sink->dsc_caps.dsc_dec_caps.is_dsc_supported = true;
+ ctx->aconnector->dc_sink = sink;
+ ctx->aconnector->mst_output_port = port;
+
+ stream = dm_mst_test_add_link_stream(test, ctx->dc_state, ctx->link, ctx->aconnector);
+ stream->ctx = ctx->dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ return stream;
+}
+
+/**
+ * dm_mst_test_compute_configs_skips_sst - non-MST streams are not considered
+ * @test: KUnit test context
+ */
+static void dm_mst_test_compute_configs_skips_sst(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_compute_configs_skips_incomplete - streams without a sink are skipped
+ * @test: KUnit test context
+ *
+ * An MST stream whose connector has neither a sink nor an output port yet is
+ * not ready for DSC bandwidth sharing.
+ */
+static void dm_mst_test_compute_configs_skips_incomplete(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_compute_configs_remove_stream_fails - a DC resource failure aborts
+ * @test: KUnit test context
+ */
+static void dm_mst_test_compute_configs_remove_stream_fails(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, dm_mst_test_remove_stream_fails);
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars),
+ -EINVAL);
+}
+
+/**
+ * dm_mst_test_compute_configs_no_recompute - an unchanged topology is left alone
+ * @test: KUnit test context
+ *
+ * The stream is DSC capable but is_dsc_need_re_compute() reports no change, so
+ * the existing configuration is kept and no DSC resource is requested.
+ */
+static void dm_mst_test_compute_configs_no_recompute(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, NULL);
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_validate_dsc_not_needed - precompute is skipped when unneeded
+ * @test: KUnit test context
+ *
+ * Without a DSC capable MST hub in the state there is nothing to precompute,
+ * so pre_validate_dsc() must succeed without touching the DM atomic state.
+ */
+static void dm_mst_test_pre_validate_dsc_not_needed(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_atomic_state *dm_state = NULL;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 1);
+
+ KUNIT_EXPECT_EQ(test, pre_validate_dsc(ctx.state, &dm_state, vars), 0);
+ KUNIT_EXPECT_NULL(test, dm_state);
+}
+
+/* Tests for pre_compute_mst_dsc_configs_for_state */
+
+/**
+ * dm_mst_test_pre_compute_configs_skips_sst - non-MST streams are not considered
+ * @test: KUnit test context
+ */
+static void dm_mst_test_pre_compute_configs_skips_sst(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_compute_configs_skips_incomplete - streams without a sink are skipped
+ * @test: KUnit test context
+ */
+static void dm_mst_test_pre_compute_configs_skips_incomplete(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_compute_configs_no_recompute - an unchanged topology is left alone
+ * @test: KUnit test context
+ *
+ * The stream is DSC capable but is_dsc_need_re_compute() reports no change, so
+ * the precompute leaves the existing configuration in place.
+ */
+static void dm_mst_test_pre_compute_configs_no_recompute(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, NULL);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/* Tests for compute_mst_dsc_configs_for_link */
+
+static const struct drm_connector_funcs dm_mst_test_dsc_link_conn_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum dp_link_encoding dm_mst_test_mst_encoding_format(const struct dc_link *link)
+{
+ return DP_8b_10b_ENCODING;
+}
+
+struct dm_mst_test_dsc_link_ctx {
+ struct drm_modeset_acquire_ctx acquire_ctx;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_dp_mst_topology_state *mst_state;
+ struct drm_atomic_commit *state;
+ struct dc_stream_state *stream;
+ struct drm_device *drm;
+ struct dc_state *dc_state;
+};
+
+static void dm_mst_test_dsc_link_drop_locks(void *data)
+{
+ struct dm_mst_test_dsc_link_ctx *ctx = data;
+
+ ctx->drm->mode_config.acquire_ctx = NULL;
+ drm_modeset_drop_locks(&ctx->acquire_ctx);
+ drm_modeset_acquire_fini(&ctx->acquire_ctx);
+}
+
+static void dm_mst_test_destroy_mst_mgr(void *data)
+{
+ struct drm_dp_mst_topology_mgr *mgr = data;
+
+ mgr->mst_state = false;
+ drm_dp_mst_topology_mgr_destroy(mgr);
+}
+
+/*
+ * Full fixture for the DSC bandwidth sharing loop: a real DRM pipe and atomic
+ * state (the DRM MST helpers need private object locking), a real topology
+ * manager, and one MST stream whose 1920x1080 timing does not fit
+ * uncompressed. @total_avail_slots decides which compression pass succeeds.
+ *
+ * The context is KUnit allocated because the modeset locks are dropped from a
+ * deferred action, long after the test body has returned.
+ */
+static struct dm_mst_test_dsc_link_ctx *
+dm_mst_test_alloc_dsc_link_ctx(struct kunit *test, int total_avail_slots)
+{
+ struct dm_mst_test_dsc_link_ctx *ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct link_service *link_srv;
+ struct resource_pool *res_pool;
+ struct drm_dp_mst_port *port;
+ struct drm_plane *primary;
+ struct drm_crtc *crtc;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ primary = drm_kunit_helper_create_primary_plane(test, ctx->drm, NULL, NULL, NULL, 0, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ crtc = drm_kunit_helper_create_crtc(test, ctx->drm, primary, NULL, NULL, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_mst_test_dsc_link_conn_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL), 0);
+ drm_mode_config_reset(ctx->drm);
+
+ KUNIT_ASSERT_EQ(test,
+ drm_dp_mst_topology_mgr_init(&ctx->aconnector->mst_mgr, ctx->drm,
+ &ctx->aconnector->dm_dp_aux.aux, 16, 4,
+ ctx->aconnector->base.base.id), 0);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_mst_test_destroy_mst_mgr,
+ &ctx->aconnector->mst_mgr), 0);
+
+ drm_modeset_acquire_init(&ctx->acquire_ctx, 0);
+ ctx->drm->mode_config.acquire_ctx = &ctx->acquire_ctx;
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_mst_test_dsc_link_drop_locks, ctx), 0);
+
+ ctx->state = drm_kunit_helper_atomic_state_alloc(test, ctx->drm, &ctx->acquire_ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->state);
+
+ crtc_state = drm_atomic_get_crtc_state(ctx->state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ crtc_state->enable = true;
+ crtc_state->active = true;
+ crtc_state->mode_changed = true;
+
+ conn_state = drm_atomic_get_connector_state(ctx->state, &ctx->aconnector->base);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+ /* Takes the connector reference that the state teardown drops again. */
+ KUNIT_ASSERT_EQ(test, drm_atomic_set_crtc_for_connector(conn_state, crtc), 0);
+
+ ctx->mst_state = drm_atomic_get_mst_topology_state(ctx->state, &ctx->aconnector->mst_mgr);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mst_state);
+ /* One time slot per 10 PBN keeps the slot counts small and exact. */
+ ctx->mst_state->pbn_div.full = dfixed_const(10);
+ ctx->mst_state->total_avail_slots = total_avail_slots;
+ /* Needed for the payload limit check; mst_primary stays NULL. */
+ ctx->aconnector->mst_mgr.mst_state = true;
+
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+
+ link_srv->mst_decide_link_encoding_format = dm_mst_test_mst_encoding_format;
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->link_srv = link_srv;
+ dc->res_pool = res_pool;
+ dc->current_state = dm_kunit_alloc_dc_state(test);
+
+ link = dm_kunit_alloc_link(test);
+ link->dc = dc;
+ link->ctx = dc->ctx;
+ link->type = dc_connection_mst_branch;
+
+ sink->ctx = dc->ctx;
+ dm_mst_test_setup_dsc_caps(test, dc, sink);
+
+ /* The payload allocation takes a reference, so start above zero. */
+ kref_init(&port->malloc_kref);
+ port->mgr = &ctx->aconnector->mst_mgr;
+ port->connector = &ctx->aconnector->base;
+ port->full_pbn = 2000;
+
+ ctx->aconnector->dc_link = link;
+ ctx->aconnector->dc_sink = sink;
+ ctx->aconnector->mst_output_port = port;
+
+ ctx->dc_state = dm_kunit_alloc_dc_state(test);
+ ctx->stream = dm_kunit_alloc_stream(test, link);
+ ctx->stream->ctx = dc->ctx;
+ ctx->stream->sink = sink;
+ ctx->stream->dm_stream_context = ctx->aconnector;
+ ctx->stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ dm_mst_test_set_dsc_timing(&ctx->stream->timing);
+ ctx->dc_state->streams[0] = ctx->stream;
+ ctx->dc_state->stream_count = 1;
+
+ return ctx;
+}
+
+/**
+ * dm_mst_test_dsc_link_fits_uncompressed - plenty of time slots means no DSC
+ * @test: KUnit test context
+ *
+ * The first pass allocates the uncompressed peak PBN and the MST check
+ * succeeds, so DSC is left disabled for the stream.
+ */
+static void dm_mst_test_dsc_link_fits_uncompressed(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 64);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_FALSE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 0U);
+ KUNIT_EXPECT_PTR_EQ(test, vars[0].aconnector, ctx->aconnector);
+}
+
+/**
+ * dm_mst_test_dsc_link_enables_compression - a tight link is compressed
+ * @test: KUnit test context
+ *
+ * The uncompressed allocation does not fit, so the driver falls back to
+ * maximum compression and then optimises the bits per pixel back up. DSC ends
+ * up enabled with a bpp above the policy minimum.
+ */
+static void dm_mst_test_dsc_link_enables_compression(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_GT(test, vars[0].bpp_x16, 0);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_dsc_link_out_of_slots - even max compression can be too big
+ * @test: KUnit test context
+ *
+ * When the fully compressed stream still exceeds the available time slots the
+ * -ENOSPC from the MST check is propagated to the caller.
+ */
+static void dm_mst_test_dsc_link_out_of_slots(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 10);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), -ENOSPC);
+}
+
+/**
+ * dm_mst_test_dsc_link_forced_dsc - forced DSC discards the uncompressed pass
+ * @test: KUnit test context
+ *
+ * With DSC forced on from debugfs the uncompressed allocation is not applied
+ * even though it fits. The MST check returned 0 rather than -ENOSPC, so the
+ * helper returns that success without programming a DSC config.
+ */
+static void dm_mst_test_dsc_link_forced_dsc(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 64);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_FALSE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_dsc_link_forced_dsc_stays_on - forced DSC is never disabled again
+ * @test: KUnit test context
+ *
+ * Once compression is needed, try_disable_dsc() only reconsiders streams left
+ * at the default DSC clock setting, so a forced stream keeps DSC enabled.
+ */
+static void dm_mst_test_dsc_link_forced_dsc_stays_on(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+}
+
+/**
+ * dm_mst_test_dsc_link_bpp_overwrite - a forced bpp overrides the computed one
+ * @test: KUnit test context
+ */
+static void dm_mst_test_dsc_link_bpp_overwrite(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_bits_per_pixel = 10 * 16;
+ ctx->aconnector->dsc_settings.dsc_num_slices_h = 2;
+ ctx->aconnector->dsc_settings.dsc_num_slices_v = 4;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_EQ(test, ctx->stream->timing.dsc_cfg.bits_per_pixel, 10 * 16);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.dsc_cfg.num_slices_h, 2U);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.dsc_cfg.num_slices_v, 4U);
+}
+
+/**
+ * dm_mst_test_dsc_link_compression_disabled - forcing DSC off keeps it off
+ * @test: KUnit test context
+ *
+ * A stream whose DSC clock is force disabled is allocated its uncompressed
+ * bandwidth in the max compression pass as well.
+ */
+static void dm_mst_test_dsc_link_compression_disabled(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_DISABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), -ENOSPC);
+}
+
+/**
+ * dm_mst_test_dsc_link_bpp_between_limits - spare slots raise the bits per pixel
+ * @test: KUnit test context
+ *
+ * With only part of the slack available the optimisation loop hands out a fair
+ * share of the free time slots and derives the resulting bits per pixel from
+ * the new PBN, landing between the policy minimum and maximum.
+ */
+static void dm_mst_test_dsc_link_bpp_between_limits(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 63);
+ /* Smaller slots leave the fair share below the full slack. */
+ ctx->mst_state->pbn_div.full = dfixed_const(4);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_GT(test, vars[0].bpp_x16, 8 * 16);
+ KUNIT_EXPECT_LT(test, vars[0].bpp_x16, 16 * 16);
}
-#endif
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
@@ -2104,6 +4058,7 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_aux_transfer_error_result),
KUNIT_CASE(dm_mst_test_aux_transfer_hpd_discon_quirk),
KUNIT_CASE(dm_mst_test_aux_transfer_non_ack_reply),
+ KUNIT_CASE(dm_mst_test_aux_transfer_oversized),
/* dm_dp_aux_fill_payload_flags tests */
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_write),
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_read),
@@ -2128,6 +4083,10 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_atomic_best_encoder),
/* dm_dp_create_fake_mst_encoders tests */
KUNIT_CASE(dm_mst_test_create_fake_mst_encoders),
+ /* dm_dp_add_mst_connector tests */
+ KUNIT_CASE(dm_mst_test_add_mst_connector_creates),
+ KUNIT_CASE(dm_mst_test_add_mst_connector_inherits_props),
+ KUNIT_CASE(dm_mst_test_add_mst_connector_init_fails),
/* dm_dp_mst_atomic_check tests */
KUNIT_CASE(dm_mst_test_atomic_check_no_old_crtc),
/* dm_dp_mst_detect tests */
@@ -2152,10 +4111,68 @@ static struct kunit_case dm_mst_types_test_cases[] = {
/* dm_dp_mst_connector_destroy tests */
KUNIT_CASE(dm_mst_test_connector_destroy_no_sink),
KUNIT_CASE(dm_mst_test_connector_destroy_releases_sink),
- /* CONFIG_DRM_AMD_DC_FP disabled public paths */
-#if !defined(CONFIG_DRM_AMD_DC_FP)
- KUNIT_CASE(dm_mst_test_fp_guarded_public_stubs),
-#endif
+ /* dp_get_link_current_set_bw tests */
+ KUNIT_CASE_PARAM(dm_mst_test_link_current_set_bw, dm_mst_link_bw_gen_params),
+ /* is_synaptics_cascaded_panamera tests */
+ KUNIT_CASE_PARAM(dm_mst_test_synaptics_cascaded, dm_mst_panamera_gen_params),
+ /* validate_dsc_caps_on_connector tests */
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_no_aux),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_aux_workaround),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_cascaded_hub),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_read_error),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_unsupported),
+ /* dm_dp_mst_is_port_support_mode tests */
+ KUNIT_CASE(dm_mst_test_port_mode_fits_without_dsc),
+ KUNIT_CASE(dm_mst_test_port_mode_no_dsc_aux),
+ KUNIT_CASE(dm_mst_test_port_mode_no_common_dsc_config),
+ KUNIT_CASE(dm_mst_test_port_mode_dsc_passthrough_fits),
+ KUNIT_CASE(dm_mst_test_port_mode_dsc_passthrough_too_narrow),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_too_slow),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_cached_bw),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_synaptics_quirk),
+ KUNIT_CASE(dm_mst_test_port_mode_upstream_vc_too_small),
+ KUNIT_CASE(dm_mst_test_port_mode_branch_throughput_exceeded),
+ /* get_conv_frl_bw tests */
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_no_pcon_support),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_not_hdmi_port),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_sink_without_frl),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_bottleneck),
+ /* log_dsc_params tests */
+ KUNIT_CASE(dm_mst_test_log_dsc_params),
+ /* find_crtc_index_in_state_by_stream tests */
+ KUNIT_CASE(dm_mst_test_find_crtc_index_matches),
+ KUNIT_CASE(dm_mst_test_find_crtc_index_no_match),
+ /* is_dsc_precompute_needed tests */
+ KUNIT_CASE_PARAM(dm_mst_test_dsc_precompute_needed, dm_mst_precompute_gen_params),
+ /* is_dsc_need_re_compute tests */
+ KUNIT_CASE(dm_mst_test_recompute_not_mst_branch),
+ KUNIT_CASE(dm_mst_test_recompute_legacy_hub_without_dsc),
+ KUNIT_CASE(dm_mst_test_recompute_no_stream_on_link),
+ KUNIT_CASE(dm_mst_test_recompute_on_mode_change),
+ KUNIT_CASE(dm_mst_test_recompute_unchanged_stream),
+ KUNIT_CASE(dm_mst_test_recompute_stream_removed),
+ KUNIT_CASE(dm_mst_test_recompute_stream_without_connector),
+ KUNIT_CASE(dm_mst_test_recompute_connector_without_crtc),
+ /* compute_mst_dsc_configs_for_state tests */
+ KUNIT_CASE(dm_mst_test_compute_configs_skips_sst),
+ KUNIT_CASE(dm_mst_test_compute_configs_skips_incomplete),
+ KUNIT_CASE(dm_mst_test_compute_configs_remove_stream_fails),
+ KUNIT_CASE(dm_mst_test_compute_configs_no_recompute),
+ /* pre_validate_dsc tests */
+ KUNIT_CASE(dm_mst_test_pre_validate_dsc_not_needed),
+ /* pre_compute_mst_dsc_configs_for_state tests */
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_skips_sst),
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_skips_incomplete),
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_no_recompute),
+ /* compute_mst_dsc_configs_for_link tests */
+ KUNIT_CASE(dm_mst_test_dsc_link_fits_uncompressed),
+ KUNIT_CASE(dm_mst_test_dsc_link_enables_compression),
+ KUNIT_CASE(dm_mst_test_dsc_link_out_of_slots),
+ KUNIT_CASE(dm_mst_test_dsc_link_forced_dsc),
+ KUNIT_CASE(dm_mst_test_dsc_link_forced_dsc_stays_on),
+ KUNIT_CASE(dm_mst_test_dsc_link_bpp_overwrite),
+ KUNIT_CASE(dm_mst_test_dsc_link_compression_disabled),
+ KUNIT_CASE(dm_mst_test_dsc_link_bpp_between_limits),
{}
};
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 1b0d3f16ef1a..a18b1d99ae85 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -506,6 +506,11 @@ static void dm_test_format_mod_supported(struct kunit *test)
KUNIT_EXPECT_FALSE(test,
amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_NV12, listed_mod));
+
+ /* 4 bytes per pixel, but its extra plane collides with the DCC metadata plane. */
+ KUNIT_EXPECT_FALSE(test,
+ amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_XRGB8888_A8,
+ listed_mod));
}
/**
@@ -2964,7 +2969,7 @@ static void dm_test_plane_create_state_initializes_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, new_state->shaper_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
KUNIT_EXPECT_EQ(test, new_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
- kfree(new_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, &new_state->base);
}
/**
@@ -2987,6 +2992,14 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, plane);
KUNIT_ASSERT_NOT_NULL(test, old_state);
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
old_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_PQ_EOTF;
old_state->hdr_mult = 0x123456789ULL;
old_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_IDENTITY;
@@ -3003,7 +3016,7 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_EXPECT_EQ(test, dup_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF);
KUNIT_EXPECT_NULL(test, dup_state->dc_state);
- kfree(dup_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, dup_base);
}
/*
@@ -3054,6 +3067,15 @@ static void dm_test_plane_duplicate_state_copies_resources(struct kunit *test)
kref_init(&dc_plane_state->refcount);
old_state->dc_state = dc_plane_state;
dm_test_attach_color_blobs(test, &adev->ddev, old_state);
+
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
plane->state = &old_state->base;
dup_base = amdgpu_dm_plane_drm_plane_duplicate_state(plane);
@@ -3673,6 +3695,328 @@ static void dm_test_atomic_async_update_copies_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, cur_state->crtc_h, 64U);
}
+/**
+ * dm_test_add_modifier_alloc_failure() - Verify the growth allocation failure.
+ * @test: KUnit test context.
+ *
+ * Verify if a failed capacity growth releases and clears the modifier list so
+ * the caller can detect the allocation failure.
+ */
+static void dm_test_add_modifier_alloc_failure(struct kunit *test)
+{
+ /* Doubling this capacity overflows the kmalloc_array() size product. */
+ u64 cap = 1ULL << 62;
+ u64 size = cap;
+ u64 *mods = kmalloc_array(1, sizeof(*mods), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, mods);
+
+ amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x1234ULL);
+
+ KUNIT_EXPECT_PTR_EQ(test, mods, NULL);
+ KUNIT_EXPECT_EQ(test, size, 1ULL << 62);
+}
+
+/**
+ * dm_test_fill_plane_buffer_attributes_gfx6() - Verify the pre-GFX9 dispatch.
+ * @test: KUnit test context.
+ *
+ * Verify if a pre-Vega family decodes tiling from the GFX6 modifier instead of
+ * taking the GFX9 or GFX12 modifier paths, and propagates the decode error for
+ * a modifier the GFX6 decoder does not understand.
+ */
+static void dm_test_fill_plane_buffer_attributes_gfx6(struct kunit *test)
+{
+ struct dc_tiling_info tiling_info = {0};
+ struct dc_plane_dcc_param dcc = {0};
+ struct dc_plane_address address = {0};
+ struct plane_size plane_size = {0};
+ struct amdgpu_framebuffer *afb;
+ struct amdgpu_device *adev;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, afb);
+
+ adev->family = AMDGPU_FAMILY_CZ;
+ afb->address = 0x80000000ULL;
+ afb->base.width = 1920;
+ afb->base.height = 1080;
+ afb->base.pitches[0] = 7680;
+ afb->base.format = drm_format_info(DRM_FORMAT_XRGB8888);
+ KUNIT_ASSERT_NOT_NULL(test, afb->base.format);
+ afb->base.modifier = AMD_FMT_MOD |
+ AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) |
+ AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) |
+ AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY);
+
+ KUNIT_EXPECT_EQ(test, dm_test_graphics_attrs(adev, afb, &tiling_info,
+ &plane_size, &dcc, &address), 0);
+ KUNIT_EXPECT_EQ(test, address.type, (int)PLN_ADDR_TYPE_GRAPHICS);
+ KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8);
+
+ afb->base.modifier = AMD_FMT_MOD |
+ AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9);
+
+ KUNIT_EXPECT_EQ(test, dm_test_graphics_attrs(adev, afb, &tiling_info,
+ &plane_size, &dcc, &address), -EINVAL);
+}
+
+/**
+ * dm_test_atomic_check_success() - Verify a fully valid plane state is accepted.
+ * @test: KUnit test context.
+ *
+ * Verify if atomic_check reports success once DC validation accepts the plane.
+ * The resource pool exposes no validate_plane callback, so DC falls back to
+ * checking the source and destination rectangles only.
+ */
+static void dm_test_atomic_check_success(struct kunit *test)
+{
+ struct dm_plane_state *dm_plane_state;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_atomic_commit *state;
+ struct resource_pool *res_pool;
+ struct amdgpu_device *adev;
+ struct drm_framebuffer *fb;
+ struct drm_plane *plane;
+
+ adev = dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state,
+ &new_crtc_state, &fb);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ res_pool->funcs = kunit_kzalloc(test, sizeof(*res_pool->funcs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool->funcs);
+
+ adev->dm.dc->res_pool = res_pool;
+
+ dm_plane_state->dc_state->src_rect.width = 100;
+ dm_plane_state->dc_state->src_rect.height = 100;
+ dm_plane_state->dc_state->dst_rect.width = 100;
+ dm_plane_state->dc_state->dst_rect.height = 100;
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), 0);
+}
+
+struct dm_test_cursor_ctx {
+ struct amdgpu_device *adev;
+ struct amdgpu_crtc *acrtc;
+ struct dm_crtc_state *crtc_state;
+ struct drm_plane_state *state;
+ struct drm_plane_state old_state;
+ struct drm_plane *plane;
+};
+
+/*
+ * Build a 64x64 cursor plane bound to an amdgpu_crtc whose DM CRTC state
+ * carries no DC stream, so the cursor update stops before programming DC.
+ */
+static struct dm_test_cursor_ctx *dm_test_alloc_cursor_ctx(struct kunit *test)
+{
+ struct amdgpu_framebuffer *afb;
+ struct dm_test_cursor_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, afb);
+
+ ctx->adev = dm_kunit_alloc_adev(test);
+ ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ ctx->plane = kunit_kzalloc(test, sizeof(*ctx->plane), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->plane);
+
+ ctx->adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+
+ ctx->acrtc->base.dev = &ctx->adev->ddev;
+ ctx->acrtc->base.state = &ctx->crtc_state->base;
+ ctx->acrtc->max_cursor_width = 64;
+ ctx->acrtc->max_cursor_height = 64;
+
+ afb->address = 0x80000000ULL;
+ afb->base.pitches[0] = 256;
+ afb->base.format = drm_format_info(DRM_FORMAT_ARGB8888);
+ KUNIT_ASSERT_NOT_NULL(test, afb->base.format);
+
+ ctx->state->fb = &afb->base;
+ ctx->state->crtc = &ctx->acrtc->base;
+ ctx->state->crtc_w = 64;
+ ctx->state->crtc_h = 64;
+
+ ctx->plane->dev = &ctx->adev->ddev;
+ ctx->plane->state = ctx->state;
+
+ return ctx;
+}
+
+/**
+ * dm_test_handle_cursor_update_disabled() - Verify the cursor-off path.
+ * @test: KUnit test context.
+ *
+ * Verify if a cursor positioned fully off the left edge is treated as disabled
+ * and returns before the cursor geometry is latched on the CRTC.
+ */
+static void dm_test_handle_cursor_update_disabled(struct kunit *test)
+{
+ struct dm_test_cursor_ctx *ctx = dm_test_alloc_cursor_ctx(test);
+
+ ctx->state->crtc_x = -64;
+
+ amdgpu_dm_plane_handle_cursor_update(ctx->plane, &ctx->old_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_width, 0);
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_height, 0);
+}
+
+/**
+ * dm_test_handle_cursor_update_no_stream() - Verify cursor attribute assembly.
+ * @test: KUnit test context.
+ *
+ * Verify if an enabled cursor latches its geometry on the CRTC and builds the
+ * DC cursor attributes, including the degamma ROM bit, before stopping at the
+ * missing DC stream.
+ */
+static void dm_test_handle_cursor_update_no_stream(struct kunit *test)
+{
+ struct dm_test_cursor_ctx *ctx = dm_test_alloc_cursor_ctx(test);
+
+ ctx->crtc_state->cm_is_degamma_srgb = true;
+ ctx->adev->dm.dc->caps.color.dpp.gamma_corr = true;
+
+ amdgpu_dm_plane_handle_cursor_update(ctx->plane, &ctx->old_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_width, 64);
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_height, 64);
+}
+
+static int dm_test_clear_dcc_tiling_count;
+
+static void dm_test_clear_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
+ struct dc_plane_state *plane_state,
+ bool clear_tiling)
+{
+ if (clear_tiling)
+ dm_test_clear_dcc_tiling_count++;
+}
+
+/**
+ * dm_test_panic_flush_disables_dcc() - Verify panic flush disables DCC.
+ * @test: KUnit test context.
+ *
+ * Verify if panic_flush asks DC to clear DCC on the active pipe, and requests
+ * the tiling teardown as well when the framebuffer is not linear.
+ */
+static void dm_test_panic_flush_disables_dcc(struct kunit *test)
+{
+ struct dc_plane_state *dc_plane_state;
+ struct dm_plane_state *dm_plane_state;
+ struct resource_pool *res_pool;
+ struct drm_framebuffer *fb;
+ struct drm_plane *plane;
+ struct dc *dc;
+
+ plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+ dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL);
+ dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
+ fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ KUNIT_ASSERT_NOT_NULL(test, dm_plane_state);
+ KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
+ KUNIT_ASSERT_NOT_NULL(test, fb);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->current_state = dm_kunit_alloc_dc_state(test);
+ dc->hwss.clear_surface_dcc_and_tiling = dm_test_clear_surface_dcc_and_tiling;
+ res_pool->pipe_count = 1;
+ dc->res_pool = res_pool;
+ dc_plane_state->ctx = dc->ctx;
+
+ fb->modifier = AMD_FMT_MOD;
+ dm_plane_state->base.fb = fb;
+ dm_plane_state->dc_state = dc_plane_state;
+ plane->state = &dm_plane_state->base;
+
+ dm_test_clear_dcc_tiling_count = 0;
+
+ amdgpu_dm_plane_panic_flush(plane);
+
+ KUNIT_EXPECT_EQ(test, dm_test_clear_dcc_tiling_count, 1);
+}
+
+/*
+ * Build a DM ready to initialize planes on a real DRM device. The plane itself
+ * is plain kzalloc'd because DRM frees it through drm_plane_helper_destroy()
+ * when the mode config is torn down.
+ */
+static struct drm_plane *dm_test_alloc_init_plane(struct kunit *test,
+ struct amdgpu_device **adev_out)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ adev = dm_kunit_alloc_adev(test);
+ adev->family = AMDGPU_FAMILY_NV;
+ adev->dm.adev = adev;
+ adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+
+ plane = kzalloc_obj(*plane, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ plane->type = DRM_PLANE_TYPE_OVERLAY;
+
+ *adev_out = adev;
+
+ return plane;
+}
+
+/**
+ * dm_test_plane_init_creates_optional_properties() - Verify optional properties.
+ * @test: KUnit test context.
+ *
+ * Verify if a Bonaire-or-newer non-cursor plane on a DCE version above 3.0.1
+ * gains the rotation property and framebuffer damage clips.
+ */
+static void dm_test_plane_init_creates_optional_properties(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ plane = dm_test_alloc_init_plane(test, &adev);
+ adev->asic_type = CHIP_BONAIRE;
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 0);
+
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_plane_init(&adev->dm, plane, 1, NULL), 0);
+
+ KUNIT_EXPECT_NOT_NULL(test, plane->rotation_property);
+ KUNIT_EXPECT_NOT_NULL(test, adev->ddev.mode_config.prop_fb_damage_clips);
+}
+
+/**
+ * dm_test_plane_init_creates_color_pipeline() - Verify color pipeline creation.
+ * @test: KUnit test context.
+ *
+ * Verify if a non-cursor plane on DCN 3.0 or newer gets a default color
+ * pipeline exposed through the COLOR_PIPELINE property.
+ */
+static void dm_test_plane_init_creates_color_pipeline(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ plane = dm_test_alloc_init_plane(test, &adev);
+ adev->dm.dc->ctx->dce_version = DCN_VERSION_3_0;
+
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_plane_init(&adev->dm, plane, 1, NULL), 0);
+
+ KUNIT_EXPECT_NOT_NULL(test, plane->color_pipeline_property);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3711,6 +4055,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_fill_plane_buffer_attributes() */
KUNIT_CASE(dm_test_fill_plane_buffer_attributes_video),
KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx12),
+ KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx6),
/* amdgpu_dm_plane_get_cursor_position() */
KUNIT_CASE(dm_test_get_cursor_position),
KUNIT_CASE(dm_test_get_cursor_position_bad_size),
@@ -3744,6 +4089,8 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_helper_cleanup_fb_no_fb),
/* amdgpu_dm_plane_handle_cursor_update() */
KUNIT_CASE(dm_test_handle_cursor_update_no_fb),
+ KUNIT_CASE(dm_test_handle_cursor_update_disabled),
+ KUNIT_CASE(dm_test_handle_cursor_update_no_stream),
/* amdgpu_dm_plane_atomic_async_update() */
KUNIT_CASE(dm_test_atomic_async_update_copies_state),
/* amdgpu_dm_plane_atomic_async_check() */
@@ -3755,8 +4102,10 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_atomic_check_helper_failure),
KUNIT_CASE(dm_test_atomic_check_color_pipeline_conflict),
KUNIT_CASE(dm_test_atomic_check_scaling_failure),
+ KUNIT_CASE(dm_test_atomic_check_success),
/* amdgpu_dm_plane_panic_flush() */
KUNIT_CASE(dm_test_panic_flush_no_dc_state),
+ KUNIT_CASE(dm_test_panic_flush_disables_dcc),
/* amdgpu_dm_plane_drm_plane_create_state() */
KUNIT_CASE(dm_test_plane_create_state_initializes_state),
/* amdgpu_dm_plane_drm_plane_duplicate_state() */
@@ -3769,6 +4118,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_add_modifier_appends_value),
KUNIT_CASE(dm_test_add_modifier_grows_capacity),
KUNIT_CASE(dm_test_add_modifier_noop_when_mods_null),
+ KUNIT_CASE(dm_test_add_modifier_alloc_failure),
/* amdgpu_dm_plane_add_modifier_dedup() */
KUNIT_CASE(dm_test_add_modifier_dedup_skips_duplicate),
KUNIT_CASE(dm_test_add_modifier_dedup_noop_when_mods_null),
@@ -3804,6 +4154,9 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_validate_dcc_not_capable_fails),
KUNIT_CASE(dm_test_validate_dcc_success_and_scan_mapping),
KUNIT_CASE(dm_test_validate_dcc_independent_64b_mismatch_fails),
+ /* amdgpu_dm_plane_init() */
+ KUNIT_CASE(dm_test_plane_init_creates_optional_properties),
+ KUNIT_CASE(dm_test_plane_init_creates_color_pipeline),
{}
};
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
index 09922e65fb16..e27f6e504395 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
@@ -413,7 +413,7 @@ static void dm_test_update_planes_adapter_sorts_and_forwards(struct kunit *test)
};
dm_test_install_dm_ops(test, &dm_test_plane_update_ops);
- KUNIT_EXPECT_TRUE(test, update_planes_and_stream_adapter(dc, UPDATE_TYPE_FAST, 3,
+ KUNIT_EXPECT_TRUE(test, update_planes_and_stream_adapter(dc, 3,
stream, stream_update, updates));
KUNIT_EXPECT_EQ(test, updates[0].surface->layer_index, 5);
KUNIT_EXPECT_EQ(test, updates[1].surface->layer_index, 3);
@@ -436,7 +436,7 @@ static void dm_test_update_planes_adapter_propagates_failure(struct kunit *test)
dm_test_plane_update_ctx = (struct dm_test_plane_update_ops_ctx) { 0 };
dm_test_install_dm_ops(test, &dm_test_plane_update_ops);
- KUNIT_EXPECT_FALSE(test, update_planes_and_stream_adapter(NULL, UPDATE_TYPE_FAST, 0,
+ KUNIT_EXPECT_FALSE(test, update_planes_and_stream_adapter(NULL, 0,
NULL, NULL, NULL));
}
@@ -3839,7 +3839,8 @@ dm_test_plane_info_ctx_alloc(struct kunit *test, struct amdgpu_device *adev,
static int dm_test_fill_plane_info(struct dm_test_plane_info_ctx *ctx)
{
- return fill_dc_plane_info_and_addr(ctx->adev, ctx->plane_state,
+ return fill_dc_plane_info_and_addr(ctx->adev, ctx->plane_state->state,
+ ctx->plane_state,
&ctx->plane_info, &ctx->address, false);
}
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index e8cdc82dcdd8..6528bfd8e76b 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -22,7 +22,7 @@
#
# Makefile for Display Core (dc) component.
-DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link dsc resource optc dpp hubbub dccg hubp dio dwb hpo mmhubbub mpc opp pg
+DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link dsc resource optc dpp hubbub dccg hubp dio dwb hpo mmhubbub mpc opp pg rmcm
ifdef CONFIG_DRM_AMD_DC_FP
@@ -66,6 +66,7 @@ FILES =
FILES += dc_dmub_srv.o
FILES += dc_fused_io.o
FILES += dc_helper.o
+FILES += dc_memory_pool.o
FILES += core/dc.o
FILES += core/dc_debug.o
FILES += core/dc_hw_sequencer.o
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 1ee98cd789f8..8839568e2adc 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -992,8 +992,6 @@ static bool dc_construct_ctx(struct dc *dc,
if (!dc_ctx)
return false;
- dc_stream_init_rmcm_3dlut(dc);
-
dc_ctx->cgs_device = init_params->cgs_device;
dc_ctx->driver_context = init_params->driver;
dc_ctx->dc = dc;
@@ -1871,6 +1869,12 @@ bool dc_validate_boot_timing(const struct dc *dc,
return false;
}
+ if (sink->edid_caps.panel_patch.disable_fec &&
+ (link->fec_state == dc_link_fec_enabled)) {
+ DC_LOG_DEBUG("boot timing validation failed due to FEC WA & FEC HW is active\n");
+ return false;
+ }
+
/* Check for enabled DIG to identify enabled display */
if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
DC_LOG_DEBUG("boot timing validation failed due to disabled DIG\n");
@@ -2274,6 +2278,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
struct dc_state *old_state;
bool subvp_prev_use = false;
+ bool dmub_locked = false;
dc_z10_restore(dc);
dc_allow_idle_optimizations(dc, false);
@@ -2325,7 +2330,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
if (dc->hwss.update_dsc_pg)
dc->hwss.update_dsc_pg(dc, context, false);
@@ -2401,7 +2406,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
dc->hwss.commit_subvp_config(dc, context);
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, true, NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
for (i = 0; i < context->stream_count; i++) {
@@ -3179,8 +3184,10 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
stream_update->vrr_active_variable || stream_update->vrr_active_fixed))
su_flags->bits.fams_changed = 1;
- if (stream_update->scaler_sharpener_update)
+ if (stream_update->scaler_sharpener_update) {
su_flags->bits.scaler_sharpener = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
if (stream_update->sharpening_required)
su_flags->bits.sharpening_required = 1;
@@ -3246,6 +3253,16 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
su_flags->bits.cursor_pos = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
+
+ if (stream_update->func_shaper) {
+ su_flags->bits.func_shaper = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
+
+ if (stream_update->lut3d_func) {
+ su_flags->bits.lut3d_func = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
}
for (int i = 0 ; i < surface_count; i++) {
@@ -4879,6 +4896,7 @@ static void commit_planes_for_stream(struct dc *dc,
bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
bool subvp_prev_use = false;
bool subvp_curr_use = false;
+ bool dmub_locked = false;
uint8_t current_stream_mask = 0;
if (should_lock_all_pipes)
@@ -4984,7 +5002,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, NULL, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
dc->hwss.interdependent_update_lock(dc, context, true);
} else {
@@ -4992,7 +5010,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
/* Lock the top pipe while updating plane addrs, since freesync requires
* plane addr update event triggers to be synchronized.
@@ -5035,7 +5053,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes,
NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
return;
}
@@ -5271,12 +5289,12 @@ static void commit_planes_for_stream(struct dc *dc,
if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
} else {
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
}
@@ -5735,127 +5753,6 @@ static bool commit_minimal_transition_state(struct dc *dc,
return true;
}
-void populate_fast_updates(struct dc_fast_update *fast_update,
- struct dc_surface_update *srf_updates,
- int surface_count,
- struct dc_stream_update *stream_update)
-{
- int i = 0;
-
- if (stream_update) {
- fast_update[0].out_transfer_func = stream_update->out_transfer_func;
- fast_update[0].output_csc_transform = stream_update->output_csc_transform;
- fast_update[0].cursor_attributes = stream_update->cursor_attributes;
- fast_update[0].cursor_position = stream_update->cursor_position;
- fast_update[0].periodic_interrupt = stream_update->periodic_interrupt;
- fast_update[0].dither_option = stream_update->dither_option;
- fast_update[0].gamut_remap = stream_update->gamut_remap;
- fast_update[0].vrr_infopacket = stream_update->vrr_infopacket;
- fast_update[0].vsc_infopacket = stream_update->vsc_infopacket;
- fast_update[0].vsp_infopacket = stream_update->vsp_infopacket;
- fast_update[0].hfvsif_infopacket = stream_update->hfvsif_infopacket;
- fast_update[0].vtem_infopacket = stream_update->vtem_infopacket;
- fast_update[0].adaptive_sync_infopacket = stream_update->adaptive_sync_infopacket;
- fast_update[0].avi_infopacket = stream_update->avi_infopacket;
- fast_update[0].hdr_static_metadata = stream_update->hdr_static_metadata;
- } else {
- fast_update[0].out_transfer_func = NULL;
- fast_update[0].output_csc_transform = NULL;
- fast_update[0].cursor_attributes = NULL;
- fast_update[0].cursor_position = NULL;
- fast_update[0].periodic_interrupt = NULL;
- fast_update[0].dither_option = NULL;
- fast_update[0].gamut_remap = NULL;
- fast_update[0].vrr_infopacket = NULL;
- fast_update[0].vsc_infopacket = NULL;
- fast_update[0].vsp_infopacket = NULL;
- fast_update[0].hfvsif_infopacket = NULL;
- fast_update[0].vtem_infopacket = NULL;
- fast_update[0].adaptive_sync_infopacket = NULL;
- fast_update[0].avi_infopacket = NULL;
- fast_update[0].hdr_static_metadata = NULL;
- }
-
- for (i = 0; i < surface_count; i++) {
- fast_update[i].flip_addr = srf_updates[i].flip_addr;
- fast_update[i].gamma = srf_updates[i].gamma;
- fast_update[i].gamut_remap_matrix = srf_updates[i].gamut_remap_matrix;
- fast_update[i].input_csc_color_matrix = srf_updates[i].input_csc_color_matrix;
- fast_update[i].coeff_reduction_factor = srf_updates[i].coeff_reduction_factor;
- fast_update[i].cursor_csc_color_matrix = srf_updates[i].cursor_csc_color_matrix;
- fast_update[i].cm_hist_control = srf_updates[i].cm_hist_control;
- }
-}
-
-static bool fast_updates_exist(const struct dc_fast_update *fast_update, int surface_count)
-{
- int i;
-
- if (fast_update[0].out_transfer_func ||
- fast_update[0].output_csc_transform ||
- fast_update[0].cursor_attributes ||
- fast_update[0].cursor_position ||
- fast_update[0].periodic_interrupt ||
- fast_update[0].dither_option ||
- fast_update[0].gamut_remap ||
- fast_update[0].vrr_infopacket ||
- fast_update[0].vsc_infopacket ||
- fast_update[0].vsp_infopacket ||
- fast_update[0].hfvsif_infopacket ||
- fast_update[0].vtem_infopacket ||
- fast_update[0].adaptive_sync_infopacket ||
- fast_update[0].avi_infopacket ||
- fast_update[0].hdr_static_metadata)
- return true;
-
- for (i = 0; i < surface_count; i++) {
- if (fast_update[i].flip_addr ||
- fast_update[i].gamma ||
- fast_update[i].gamut_remap_matrix ||
- fast_update[i].input_csc_color_matrix ||
- fast_update[i].cursor_csc_color_matrix ||
- fast_update[i].cm_hist_control ||
- fast_update[i].coeff_reduction_factor)
- return true;
- }
-
- return false;
-}
-
-bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count)
-{
- int i;
-
- if (fast_update[0].out_transfer_func ||
- fast_update[0].output_csc_transform ||
- fast_update[0].gamut_remap ||
- fast_update[0].cursor_attributes ||
- fast_update[0].cursor_position ||
- fast_update[0].periodic_interrupt ||
- fast_update[0].dither_option ||
- fast_update[0].vrr_infopacket ||
- fast_update[0].vsc_infopacket ||
- fast_update[0].vsp_infopacket ||
- fast_update[0].hfvsif_infopacket ||
- fast_update[0].vtem_infopacket ||
- fast_update[0].adaptive_sync_infopacket ||
- fast_update[0].avi_infopacket ||
- fast_update[0].hdr_static_metadata)
- return true;
-
- for (i = 0; i < surface_count; i++) {
- if (fast_update[i].input_csc_color_matrix ||
- fast_update[i].gamma ||
- fast_update[i].gamut_remap_matrix ||
- fast_update[i].coeff_reduction_factor ||
- fast_update[i].cm_hist_control ||
- fast_update[i].cursor_csc_color_matrix)
- return true;
- }
-
- return false;
-}
-
static bool full_update_required_weak(
const struct dc *dc,
const struct dc_surface_update *srf_updates,
@@ -5884,67 +5781,6 @@ static bool full_update_required_weak(
return false;
}
-static bool full_update_required(
- const struct dc *dc,
- const struct dc_surface_update *srf_updates,
- int surface_count,
- const struct dc_stream_update *stream_update,
- const struct dc_stream_state *stream)
-{
- if (full_update_required_weak(dc, srf_updates, surface_count, stream_update, stream))
- return true;
-
- for (int i = 0; i < surface_count; i++) {
- if (srf_updates &&
- (srf_updates[i].plane_info ||
- srf_updates[i].scaling_info ||
- (srf_updates[i].hdr_mult.value &&
- srf_updates[i].hdr_mult.value != srf_updates->surface->hdr_mult.value) ||
- (srf_updates[i].sdr_white_level_nits &&
- srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) ||
- srf_updates[i].in_transfer_func ||
- srf_updates[i].surface->force_full_update ||
- (srf_updates[i].flip_addr &&
- srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface)))
- return true;
- }
-
- if (stream_update &&
- (((stream_update->src.height != 0 && stream_update->src.width != 0) ||
- (stream_update->dst.height != 0 && stream_update->dst.width != 0) ||
- stream_update->integer_scaling_update) ||
- stream_update->abm_level ||
- stream_update->dpms_off ||
- stream_update->allow_freesync ||
- stream_update->vrr_active_variable ||
- stream_update->vrr_active_fixed ||
- stream_update->output_color_space ||
- stream_update->wb_update ||
- stream_update->dsc_config ||
- stream_update->mst_bw_update ||
- stream_update->func_shaper ||
- stream_update->lut3d_func ||
- stream_update->pending_test_pattern ||
- stream_update->crtc_timing_adjust ||
- stream_update->scaler_sharpener_update ||
- stream_update->hw_cursor_req))
- return true;
-
- return false;
-}
-
-static bool fast_update_only(
- const struct dc *dc,
- const struct dc_fast_update *fast_update,
- const struct dc_surface_update *srf_updates,
- int surface_count,
- const struct dc_stream_update *stream_update,
- const struct dc_stream_state *stream)
-{
- return fast_updates_exist(fast_update, surface_count)
- && !full_update_required(dc, srf_updates, surface_count, stream_update, stream);
-}
-
static bool update_planes_and_stream_v2(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
@@ -5952,7 +5788,6 @@ static bool update_planes_and_stream_v2(struct dc *dc,
{
struct dc_state *context;
enum dc_update_type update_type;
- struct dc_fast_update fast_update[MAX_SURFACES] = {0};
/* In cases where MPO and split or ODM are used transitions can
* cause underflow. Apply stream configuration with minimal pipe
@@ -5960,11 +5795,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
*/
bool force_minimal_pipe_splitting = 0;
bool is_plane_addition = 0;
- bool is_fast_update_only;
- populate_fast_updates(fast_update, srf_updates, surface_count, stream_update);
- is_fast_update_only = fast_update_only(dc, fast_update, srf_updates,
- surface_count, stream_update, stream);
force_minimal_pipe_splitting = could_mpcc_tree_change_for_active_pipes(
dc,
stream,
@@ -6002,7 +5833,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
commit_minimal_transition_state_in_dc_update(dc, context, stream,
srf_updates, surface_count);
- if (is_fast_update_only && !dc->check_config.enable_legacy_fast_update) {
+ if (update_type == UPDATE_TYPE_FAST && !dc->check_config.enable_legacy_fast_update) {
commit_planes_for_stream_fast(dc,
srf_updates,
surface_count,
@@ -6038,13 +5869,8 @@ static void commit_planes_and_stream_update_on_current_context(struct dc *dc,
struct dc_stream_update *stream_update,
enum dc_update_type update_type)
{
- struct dc_fast_update fast_update[MAX_SURFACES] = {0};
-
ASSERT(update_type < UPDATE_TYPE_FULL);
- populate_fast_updates(fast_update, srf_updates, surface_count,
- stream_update);
- if (fast_update_only(dc, fast_update, srf_updates, surface_count,
- stream_update, stream) &&
+ if (update_type == UPDATE_TYPE_FAST &&
!dc->check_config.enable_legacy_fast_update)
commit_planes_for_stream_fast(dc,
srf_updates,
@@ -8240,23 +8066,6 @@ static bool update_planes_and_stream_prepare_v3(
ASSERT(scratch->flow == UPDATE_V3_FLOW_INVALID);
dc_exit_ips_for_hw_access(scratch->dc);
- /* HWSS path determination needs to be done prior to updating the surface and stream states. */
- struct dc_fast_update fast_update[MAX_SURFACES] = { 0 };
-
- populate_fast_updates(fast_update,
- scratch->surface_updates,
- scratch->surface_count,
- scratch->stream_update);
-
- const bool is_hwss_fast_path_only =
- fast_update_only(scratch->dc,
- fast_update,
- scratch->surface_updates,
- scratch->surface_count,
- scratch->stream_update,
- scratch->stream) &&
- !scratch->dc->check_config.enable_legacy_fast_update;
-
if (!update_planes_and_stream_state(
scratch->dc,
scratch->surface_updates,
@@ -8272,7 +8081,8 @@ static bool update_planes_and_stream_prepare_v3(
if (scratch->new_context == scratch->dc->current_state) {
ASSERT(scratch->update_type < UPDATE_TYPE_FULL);
- scratch->flow = is_hwss_fast_path_only
+ scratch->flow = (scratch->update_type == UPDATE_TYPE_FAST &&
+ !scratch->dc->check_config.enable_legacy_fast_update)
? UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST
: UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL;
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index b54466e4f42b..6ed22b2e9c74 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1319,11 +1319,7 @@ void hwss_build_fast_sequence(struct dc *dc,
cursor_pipe_to_program = current_pipe;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_begin_cursor_offload_update(&seq_state, dc, current_pipe);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = current_pipe;
@@ -1364,22 +1360,14 @@ void hwss_build_fast_sequence(struct dc *dc,
hwss_add_set_cursor_sdr_white_level(&seq_state, current_pipe);
if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- (*num_steps)++;
+ hwss_add_update_cursor_offload_pipe(&seq_state, dc, current_pipe);
}
}
/* Unlock cursor attributes after all pipes have been programmed */
if (cursor_pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.pipe_ctx =
- cursor_pipe_to_program;
- block_sequence[*num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_commit_cursor_offload_update(&seq_state, dc, cursor_pipe_to_program);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = cursor_pipe_to_program;
@@ -1417,11 +1405,7 @@ void hwss_build_fast_sequence(struct dc *dc,
cursor_pipe_to_program = current_pipe;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_begin_cursor_offload_update(&seq_state, dc, current_pipe);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = current_pipe;
@@ -1437,11 +1421,7 @@ void hwss_build_fast_sequence(struct dc *dc,
(*num_steps)++;
if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- (*num_steps)++;
+ hwss_add_update_cursor_offload_pipe(&seq_state, dc, current_pipe);
}
if (dc->ctx->dmub_srv)
@@ -1453,11 +1433,7 @@ void hwss_build_fast_sequence(struct dc *dc,
/* Unlock cursor position after all pipes have been programmed */
if (cursor_pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.pipe_ctx =
- cursor_pipe_to_program;
- block_sequence[*num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_commit_cursor_offload_update(&seq_state, dc, cursor_pipe_to_program);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = cursor_pipe_to_program;
@@ -1495,7 +1471,7 @@ void hwss_build_fast_sequence(struct dc *dc,
block_sequence[*num_steps].func = HUBP_PROGRAM_TRIPLEBUFFER;
(*num_steps)++;
}
- if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_bits.addr_update) {
+ if (dc->hwss.prepare_plane_addr_update && current_mpc_pipe->plane_state->update_bits.addr_update) {
if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) &&
stream_status->mall_stream_config.type == SUBVP_MAIN) {
block_sequence[*num_steps].params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
@@ -1505,15 +1481,14 @@ void hwss_build_fast_sequence(struct dc *dc,
(*num_steps)++;
}
- block_sequence[*num_steps].params.update_plane_addr_params.dc = dc;
- block_sequence[*num_steps].params.update_plane_addr_params.pipe_ctx = current_mpc_pipe;
- block_sequence[*num_steps].func = HUBP_UPDATE_PLANE_ADDR;
- (*num_steps)++;
+ hwss_add_hubp_update_plane_addr(&seq_state, dc, current_mpc_pipe);
}
if (current_mpc_pipe->plane_state->update_bits.lut_3d &&
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_dma_enable &&
- current_mpc_pipe->plane_state->cm.flags.bits.shaper_enable &&
+ /* RMCM drives the 3DLUT without a shaper */
+ (current_mpc_pipe->plane_state->cm.flags.bits.shaper_enable ||
+ current_mpc_pipe->plane_state->cm.flags.bits.rmcm_enable) &&
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_enable &&
current_mpc_pipe->plane_res.hubp->funcs->hubp_enable_3dlut_fl) {
block_sequence[*num_steps].params.hubp_enable_3dlut_fl_params.hubp =
@@ -1534,6 +1509,7 @@ void hwss_build_fast_sequence(struct dc *dc,
primary_dpp_pipe->plane_res.hubp : current_mpc_pipe->plane_res.hubp,
.ipp = current_mpc_pipe->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = current_mpc_pipe->plane_res.rmcm,
.mpcc_id = current_mpc_pipe->plane_res.mpcc_inst,
.stream = current_mpc_pipe->stream,
.plane_state = current_mpc_pipe->plane_state,
@@ -1734,8 +1710,11 @@ void hwss_execute_sequence(struct dc *dc,
params->program_triplebuffer_params.enableTripleBuffer);
break;
case HUBP_UPDATE_PLANE_ADDR:
- dc->hwss.update_plane_addr(params->update_plane_addr_params.dc,
- params->update_plane_addr_params.pipe_ctx);
+ params->update_plane_addr_params.hubp->funcs->hubp_program_surface_flip_and_addr(
+ params->update_plane_addr_params.hubp,
+ &params->update_plane_addr_params.address,
+ params->update_plane_addr_params.flip_immediate,
+ params->update_plane_addr_params.dcc);
break;
case DPP_SET_INPUT_TRANSFER_FUNC:
hws->funcs.set_input_transfer_func(&params->set_input_transfer_func_params);
@@ -2127,20 +2106,20 @@ void hwss_execute_sequence(struct dc *dc,
case HUBP_MEM_PROGRAM_VIEWPORT:
hwss_hubp_mem_program_viewport(params);
break;
- case ABORT_CURSOR_OFFLOAD_UPDATE:
- hwss_abort_cursor_offload_update(params);
- break;
case HWSS_CURSOR_LOCK:
hwss_cursor_lock(params);
break;
case HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE:
- hwss_begin_cursor_offload_update(params);
+ hwss_begin_cursor_offload_update(dc, params);
break;
case HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE:
- hwss_commit_cursor_offload_update(params);
+ hwss_commit_cursor_offload_update(dc, params);
break;
case HWSS_UPDATE_CURSOR_OFFLOAD_PIPE:
- hwss_update_cursor_offload_pipe(params);
+ hwss_update_cursor_offload_pipe(dc, params);
+ break;
+ case ABORT_CURSOR_OFFLOAD_UPDATE:
+ hwss_abort_cursor_offload_update(dc, params);
break;
case DC_SEND_CURSOR_INFO_TO_DMU:
hwss_send_cursor_info_to_dmu(params);
@@ -2366,9 +2345,19 @@ void hwss_add_hubp_update_plane_addr(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ struct hubp *hubp = pipe_ctx->plane_res.hubp;
+
+ if (!dc->hwss.prepare_plane_addr_update || !hubp || !hubp->funcs->hubp_program_surface_flip_and_addr)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params.pipe_ctx = pipe_ctx;
+ struct update_plane_addr_params *params =
+ &seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params;
+
+ dc->hwss.prepare_plane_addr_update(dc, pipe_ctx,
+ &params->address, &params->flip_immediate);
+ params->hubp = hubp;
+ params->dcc = pipe_ctx->plane_state ? pipe_ctx->plane_state->dcc.enable : false;
seq_state->steps[*seq_state->num_steps].func = HUBP_UPDATE_PLANE_ADDR;
(*seq_state->num_steps)++;
}
@@ -2392,6 +2381,7 @@ void hwss_add_dpp_set_input_transfer_func(struct block_sequence_state *seq_state
primary_dpp_pipe->plane_res.hubp : pipe_ctx->plane_res.hubp,
.ipp = pipe_ctx->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = pipe_ctx->plane_res.rmcm,
.mpcc_id = pipe_ctx->plane_res.mpcc_inst,
.plane_state = pipe_ctx->plane_state,
.stream = pipe_ctx->stream,
@@ -4321,15 +4311,6 @@ void hwss_hubp_mem_program_viewport(union block_sequence_params *params)
hubp->funcs->mem_program_viewport(hubp, viewport, viewport_c);
}
-void hwss_abort_cursor_offload_update(union block_sequence_params *params)
-{
- struct dc *dc = params->abort_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->abort_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
-}
-
void hwss_cursor_lock(union block_sequence_params *params)
{
struct dc *dc = params->cursor_lock_params.dc;
@@ -4340,31 +4321,45 @@ void hwss_cursor_lock(union block_sequence_params *params)
dc->hwss.cursor_lock(dc, pipe_ctx, lock);
}
-void hwss_begin_cursor_offload_update(union block_sequence_params *params)
+void hwss_begin_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->begin_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->begin_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+ if (dc->hwss.begin_cursor_offload_update)
+ dc->hwss.begin_cursor_offload_update(
+ params->begin_cursor_offload_update_params.dmub,
+ params->begin_cursor_offload_update_params.dpp,
+ params->begin_cursor_offload_update_params.hubp,
+ params->begin_cursor_offload_update_params.stream_idx);
}
-void hwss_commit_cursor_offload_update(union block_sequence_params *params)
+void hwss_commit_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->commit_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->commit_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe_ctx);
+ if (dc->hwss.commit_cursor_offload_update)
+ dc->hwss.commit_cursor_offload_update(
+ params->commit_cursor_offload_update_params.dmub,
+ params->commit_cursor_offload_update_params.dpp,
+ params->commit_cursor_offload_update_params.hubp,
+ params->commit_cursor_offload_update_params.stream_idx);
}
-void hwss_update_cursor_offload_pipe(union block_sequence_params *params)
+void hwss_update_cursor_offload_pipe(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->update_cursor_offload_pipe_params.dc;
- struct pipe_ctx *pipe_ctx = params->update_cursor_offload_pipe_params.pipe_ctx;
+ if (dc->hwss.update_cursor_offload_pipe)
+ dc->hwss.update_cursor_offload_pipe(
+ params->update_cursor_offload_pipe_params.dmub,
+ params->update_cursor_offload_pipe_params.stream_idx,
+ params->update_cursor_offload_pipe_params.pipe_idx,
+ params->update_cursor_offload_pipe_params.dpp,
+ params->update_cursor_offload_pipe_params.hubp);
+}
- if (dc && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+void hwss_abort_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
+{
+ if (dc->hwss.abort_cursor_offload_update)
+ dc->hwss.abort_cursor_offload_update(
+ params->abort_cursor_offload_update_params.dmub,
+ params->abort_cursor_offload_update_params.dpp,
+ params->abort_cursor_offload_update_params.hubp,
+ params->abort_cursor_offload_update_params.stream_idx);
}
void hwss_send_cursor_info_to_dmu(union block_sequence_params *params)
@@ -4663,6 +4658,7 @@ void hwss_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx)
primary_dpp_pipe->plane_res.hubp : pipe_ctx->plane_res.hubp,
.ipp = pipe_ctx->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = pipe_ctx->plane_res.rmcm,
.mpcc_id = pipe_ctx->plane_res.mpcc_inst,
.plane_state = pipe_ctx->plane_state,
.stream = pipe_ctx->stream,
@@ -5755,18 +5751,6 @@ void hwss_add_hubp_mem_program_viewport(struct block_sequence_state *seq_state,
}
}
-void hwss_add_abort_cursor_offload_update(struct block_sequence_state *seq_state,
- struct dc *dc,
- struct pipe_ctx *pipe_ctx)
-{
- if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].func = ABORT_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.pipe_ctx = pipe_ctx;
- (*seq_state->num_steps)++;
- }
-}
-
void hwss_add_set_cursor_attribute(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
@@ -5907,18 +5891,6 @@ void hwss_add_tg_get_frame_count(struct block_sequence_state *seq_state,
}
}
-void hwss_add_begin_cursor_offload_update(struct block_sequence_state *seq_state,
- struct dc *dc,
- struct pipe_ctx *pipe_ctx)
-{
- if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.pipe_ctx = pipe_ctx;
- (*seq_state->num_steps)++;
- }
-}
-
void hwss_add_cursor_lock(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx,
@@ -5967,10 +5939,27 @@ void hwss_add_update_cursor_offload_pipe(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ const struct pipe_ctx *top_pipe;
+
+ if (!dc->hwss.update_cursor_offload_pipe)
+ return;
+
+ top_pipe = resource_get_otg_master(pipe_ctx);
+ if (!top_pipe)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
seq_state->steps[*seq_state->num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.pipe_ctx = pipe_ctx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.pipe_idx =
+ pipe_ctx->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.hubp =
+ pipe_ctx->plane_res.hubp;
(*seq_state->num_steps)++;
}
}
@@ -5979,10 +5968,67 @@ void hwss_add_commit_cursor_offload_update(struct block_sequence_state *seq_stat
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
seq_state->steps[*seq_state->num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.pipe_ctx = pipe_ctx;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_begin_cursor_offload_update(struct block_sequence_state *seq_state,
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_abort_cursor_offload_update(struct block_sequence_state *seq_state,
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = ABORT_CURSOR_OFFLOAD_UPDATE;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
(*seq_state->num_steps)++;
}
}
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 f9b8e9474b4c..ecbd2b4a0c22 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -1557,11 +1557,21 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx,
}
}
-enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format)
+enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format,
+ enum dc_scaling_linearity scaling_linearity)
{
- if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb) //420 Formats
+ bool scaling_in_linear = (scaling_linearity == DC_SCALING_LINEARITY_LINEAR);
+ bool is_420_format = (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN &&
+ format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb);
+ bool is_422_format = (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb &&
+ format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END);
+
+ /* UPSP (chroma upsampling) is only needed when subsampled YUV is scaled in
+ * linear space.
+ */
+ if (scaling_in_linear && is_420_format)
return UPSP_HORIZONTAL_VERTICAL_UPSAMPLING;
- if (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) //422 Formats
+ if (scaling_in_linear && is_422_format)
return UPSP_HORIZONTAL_UPSAMPLING_ONLY;
return UPSP_BYPASS;
}
@@ -1611,7 +1621,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
- pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format);
+ pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format, plane_state->scaling_linearity);
// Convert pipe_ctx to respective input params for SPL
translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
@@ -3379,6 +3389,95 @@ static bool acquire_secondary_dpp_pipes_and_add_plane(
return true;
}
+/*
+ * resource_assign_rmcm() - Assign the RMCM instances for a whole context
+ *
+ * RMCM is pre-blend, so every pipe asking for one needs its own instance. Ownership is
+ * tracked per instance in res_ctx->rmcm_in_use[]; the owning pipe is the one holding the
+ * matching plane_res.rmcm pointer.
+ *
+ * A pipe that already drives an RMCM keeps it, so a plane that is only now asking never
+ * evicts one that is already using an instance - it simply gets none when the pool is
+ * exhausted. This has to see the finished context, hence one pass over all pipes rather
+ * than one per appended plane.
+ */
+void resource_assign_rmcm(
+ struct dc_state *new_ctx,
+ const struct dc_state *cur_ctx,
+ const struct resource_pool *pool)
+{
+ struct rmcm *held[MAX_PIPES] = { NULL };
+ unsigned int p;
+ int i;
+
+ /* new_ctx and cur_ctx can be the same object, so snapshot before clearing */
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
+ held[p] = cur_ctx ? cur_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm : NULL;
+
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
+ new_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm = NULL;
+
+ for (i = 0; i < MAX_RMCM_INST; i++)
+ new_ctx->res_ctx.rmcm_in_use[i] = false;
+
+ /* incumbents first, so a later pipe cannot take an instance out from under them */
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
+ struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
+
+ if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
+ continue;
+
+ if (!held[p] || new_ctx->res_ctx.rmcm_in_use[held[p]->inst])
+ continue;
+
+ pipe->plane_res.rmcm = held[p];
+ new_ctx->res_ctx.rmcm_in_use[held[p]->inst] = true;
+ }
+
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
+ struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
+
+ if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
+ continue;
+
+ if (pipe->plane_res.rmcm)
+ continue;
+
+ for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ if (!pool->rmcm[i] || new_ctx->res_ctx.rmcm_in_use[i])
+ continue;
+
+ pipe->plane_res.rmcm = pool->rmcm[i];
+ new_ctx->res_ctx.rmcm_in_use[i] = true;
+ break;
+ }
+ }
+}
+
+/*
+ * resource_release_rmcm() - Release an RMCM instance for a pipe.
+ *
+ * Marks the instance free and NULLs the caller's pointer.
+ */
+void resource_release_rmcm(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct rmcm **rmcm)
+{
+ int i;
+
+ if (!*rmcm)
+ return;
+
+ for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ if (pool->rmcm[i] == *rmcm) {
+ res_ctx->rmcm_in_use[i] = false;
+ *rmcm = NULL;
+ return;
+ }
+ }
+}
+
bool resource_append_dpp_pipes_for_plane_composition(
struct dc_state *new_ctx,
struct dc_state *cur_ctx,
@@ -3404,6 +3503,12 @@ bool resource_append_dpp_pipes_for_plane_composition(
pool, plane_state);
}
+ /* Idempotent, so the last append of a commit leaves the final assignment behind.
+ * Releasing is driven by the MPC_RMCM_CNTL mirror (see dcn42_release_rmcm_from_mpcc).
+ */
+ if (success)
+ resource_assign_rmcm(new_ctx, cur_ctx, pool);
+
return success;
}
@@ -3418,6 +3523,12 @@ void resource_remove_dpp_pipes_for_plane_composition(
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->plane_state == plane_state) {
+ /* Release RMCM instance for this pipe */
+ if (pipe_ctx->plane_res.rmcm)
+ resource_release_rmcm(&context->res_ctx,
+ pool,
+ &pipe_ctx->plane_res.rmcm);
+
if (pipe_ctx->top_pipe)
pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
@@ -4470,11 +4581,31 @@ enum dc_status resource_validate_probe_set(struct dc *dc,
return DC_NOT_SUPPORTED;
for (i = 0; i < probe_count; i++) {
- if (probes[i].target_state == DC_PROBE_MEASURING)
- return DC_NOT_SUPPORTED;
-
- if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ switch (probes[i].type) {
+ /* These global probes support a one-frame measurement and reset. */
+ case DC_PROBE_PEAK_MEM_BW:
+ case DC_PROBE_PEAK_MEM_BW_STRESSED:
+ case DC_PROBE_AVG_MEM_BW:
+ case DC_PROBE_MEM_LATENCY:
+ case DC_PROBE_PREFETCH_DATA_SIZE:
+ if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ return DC_NOT_SUPPORTED;
+ if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURED)
+ return DC_NOT_SUPPORTED;
+ break;
+ /* The global urgent assertion counter additionally supports polling. */
+ case DC_PROBE_URGENT_ASSERTION_COUNT:
+ if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ return DC_NOT_SUPPORTED;
+ if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURED)
+ return DC_NOT_SUPPORTED;
+ break;
+ default:
return DC_NOT_SUPPORTED;
+ }
if (probes[i].type == DC_PROBE_PEAK_MEM_BW_STRESSED &&
!dc->res_pool->lsdma_scratch.buffer)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index 1e4fe2f941ca..edb50c23ce24 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -467,8 +467,6 @@ enum dc_status dc_state_remove_stream(
return DC_ERROR_UNEXPECTED;
}
- dc_stream_release_3dlut_for_stream(dc, stream);
-
dc_stream_release(state->streams[i]);
state->stream_count--;
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 35d4d0d5ae34..8d3aacc7b96c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -323,7 +323,12 @@ void program_cursor_attributes(
pipe_to_program = pipe_ctx;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.begin_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
} else {
dc->hwss.cursor_lock(dc, pipe_to_program, true);
if (pipe_to_program->next_odm_pipe)
@@ -335,13 +340,24 @@ void program_cursor_attributes(
update_cursor_info_to_dmu(dc, pipe_ctx);
if (dc->hwss.set_cursor_sdr_white_level)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
- if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+ if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.update_cursor_offload_pipe(dc->ctx->dmub_srv->dmub,
+ top_pipe->pipe_idx, pipe_ctx->pipe_idx,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp);
+ }
}
if (pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_to_program);
+
+ if (top_pipe)
+ dc->hwss.commit_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_to_program->plane_res.dpp, pipe_to_program->plane_res.hubp,
+ top_pipe->pipe_idx);
} else {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
if (pipe_to_program->next_odm_pipe)
@@ -484,24 +500,42 @@ void program_cursor_position(
if (!pipe_to_program) {
pipe_to_program = pipe_ctx;
- if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
- else
+ if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.begin_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ } else {
dc->hwss.cursor_lock(dc, pipe_to_program, true);
+ }
}
dc->hwss.set_cursor_position(pipe_ctx);
- if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+ if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.update_cursor_offload_pipe(dc->ctx->dmub_srv->dmub,
+ top_pipe->pipe_idx, pipe_ctx->pipe_idx,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp);
+ }
update_cursor_info_to_dmu(dc, pipe_ctx);
}
if (pipe_to_program) {
- if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
- else
+ if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_to_program);
+
+ if (top_pipe)
+ dc->hwss.commit_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_to_program->plane_res.dpp, pipe_to_program->plane_res.hubp,
+ top_pipe->pipe_idx);
+ } else {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
+ }
}
}
@@ -1004,72 +1038,6 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
}
}
-/* TODO - move to per plane ownership? */
-/*
-* dc_stream_get_3dlut()
-* Requirements:
-* 1. Is stream already owns an RMCM instance, return it.
-* 2. If it doesn't and we don't need to allocate, return NULL.
-* 3. If there's a free RMCM instance, assign to stream and return it.
-* 4. If no free RMCM instances, return NULL.
-*/
-
-struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream,
- bool allocate_one)
-{
- unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
-
- // see if one is allocated for this stream
- for (unsigned int i = 0; i < num_rmcm; i++) {
- if (dc->res_pool->rmcm_3dlut[i].isInUse &&
- dc->res_pool->rmcm_3dlut[i].stream == stream)
- return &dc->res_pool->rmcm_3dlut[i];
- }
-
- //case: not found one, and dont need to allocate
- if (!allocate_one)
- return NULL;
-
- //see if there is an unused 3dlut, allocate
- for (unsigned int i = 0; i < num_rmcm; i++) {
- if (!dc->res_pool->rmcm_3dlut[i].isInUse) {
- dc->res_pool->rmcm_3dlut[i].isInUse = true;
- dc->res_pool->rmcm_3dlut[i].stream = stream;
- return &dc->res_pool->rmcm_3dlut[i];
- }
- }
-
- //dont have a 3dlut
- return NULL;
-}
-
-
-void dc_stream_release_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream)
-{
- struct dc_rmcm_3dlut *rmcm_3dlut =
- dc_stream_get_3dlut_for_stream(dc, stream, false);
-
- if (rmcm_3dlut) {
- rmcm_3dlut->isInUse = false;
- rmcm_3dlut->stream = NULL;
- }
-}
-
-
-void dc_stream_init_rmcm_3dlut(struct dc *dc)
-{
- unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
-
- for (unsigned int i = 0; i < num_rmcm; i++) {
- dc->res_pool->rmcm_3dlut[i].isInUse = false;
- dc->res_pool->rmcm_3dlut[i].stream = NULL;
- }
-}
-
/*
* Finds the greatest index in refresh_rate_hz that contains a value <= refresh
*/
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 4ecd5699ac5e..5174a0098e75 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -37,6 +37,7 @@
#include "link_service_types.h"
#include "grph_object_ctrl_defs.h"
#include <inc/hw/opp.h>
+#include <inc/hw/rmcm.h>
#include "hwss/hw_sequencer.h"
#include "inc/compressor.h"
@@ -66,7 +67,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
-#define DC_VER "3.2.397"
+#define DC_VER "3.2.398"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
@@ -111,10 +112,10 @@ struct frl_cap_chk_params_fixed31_32 {
int lanes;
struct fixed31_32 f_pixel_clock_nominal; /* Pixel Clock rate (Hz) */
struct fixed31_32 r_bit_nominal; /* FRL bitrate (bps) */
- int audio_packet_type;
+ unsigned int audio_packet_type;
struct fixed31_32 f_audio; /* Audio rate (Hz) */
- int h_active; /* Active pixels per line */
- int h_blank; /* Blanking pixels per line */
+ uint32_t h_active; /* Active pixels per line */
+ uint32_t h_blank; /* Blanking pixels per line */
int bpc; /* Bits per component */
int vic; /* Video Identification Code */
@@ -1287,6 +1288,7 @@ struct dc_debug_options {
bool dml21_force_pstate_method;
uint32_t dml21_force_pstate_method_values[MAX_PIPES];
uint32_t dml21_disable_pstate_method_mask;
+ bool force_optional_uclk_pstate_support;
union fw_assisted_mclk_switch_version fams_version;
union dmub_fams2_global_feature_config fams2_config;
bool fams2_imm_restore_drr;
@@ -1514,11 +1516,6 @@ struct lut_mem_mapping {
uint16_t size;
};
-struct dc_rmcm_3dlut {
- bool isInUse;
- const struct dc_stream_state *stream;
-};
-
struct dc_3dlut {
struct kref refcount;
struct tetrahedral_params lut_3d;
@@ -2094,32 +2091,6 @@ struct dc_scaling_info {
struct scaling_taps scaling_quality;
};
-struct dc_fast_update {
- const struct dc_flip_addrs *flip_addr;
- const struct dc_gamma *gamma;
- const struct colorspace_transform *gamut_remap_matrix;
- const struct dc_csc_transform *input_csc_color_matrix;
- const struct fixed31_32 *coeff_reduction_factor;
- struct dc_transfer_func *out_transfer_func;
- struct dc_csc_transform *output_csc_transform;
- const struct dc_csc_transform *cursor_csc_color_matrix;
- struct cm_hist_control *cm_hist_control;
- /* stream-level fast updates */
- const struct colorspace_transform *gamut_remap;
- const struct dc_cursor_attributes *cursor_attributes;
- const struct dc_cursor_position *cursor_position;
- const struct periodic_interrupt_config *periodic_interrupt;
- const enum dc_dither_option *dither_option;
- struct dc_info_packet *vrr_infopacket;
- struct dc_info_packet *vsc_infopacket;
- struct dc_info_packet *vsp_infopacket;
- struct dc_info_packet *hfvsif_infopacket;
- struct dc_info_packet *vtem_infopacket;
- struct dc_info_packet *adaptive_sync_infopacket;
- struct dc_info_packet *avi_infopacket;
- struct dc_info_packet *hdr_static_metadata;
-};
-
struct dc_surface_update {
struct dc_plane_state *surface;
@@ -2227,6 +2198,7 @@ struct dc_probe_latencies {
/**
* struct dc_probe_status - results for a probe.
* @valid: true if a measurement was latched.
+ * @measuring: true if the hardware counter is currently running.
* @type: type of the probe that produced this result.
* @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
* @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
@@ -2236,6 +2208,7 @@ struct dc_probe_latencies {
*/
struct dc_probe_status {
bool valid;
+ bool measuring;
enum dc_probe_type type;
union {
uint32_t bandwidth_mbps;
@@ -2423,11 +2396,6 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc);
void get_audio_check(struct audio_info *aud_modes,
struct audio_check *aud_chk);
-bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count);
-void populate_fast_updates(struct dc_fast_update *fast_update,
- struct dc_surface_update *srf_updates,
- int surface_count,
- struct dc_stream_update *stream_update);
/*
* Set up streams and links associated to drive sinks
* The streams parameter is an absolute set of all active streams.
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index d08dd372179c..1e7071f8d53f 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -41,8 +41,6 @@
#define DC_LOGGER CTX->logger
#define GPINT_RETRY_NUM 20
-#define MAX_WAIT_US 500000
-
static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc,
struct dmub_srv *dmub)
{
@@ -93,7 +91,7 @@ bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv)
dmub = dc_dmub_srv->dmub;
do {
- status = dmub_srv_wait_for_pending(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_pending(dmub, DMUB_CMD_DEFAULT_MAX_WAIT_US);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
if (status != DMUB_STATUS_OK) {
@@ -123,7 +121,7 @@ void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv)
struct dc_context *dc_ctx = dc_dmub_srv->ctx;
enum dmub_status status = DMUB_STATUS_OK;
- status = dmub_srv_wait_for_inbox0_ack(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_inbox0_ack(dmub, DMUB_CMD_DEFAULT_MAX_WAIT_US);
if (status != DMUB_STATUS_OK) {
DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n");
dc_dmub_srv_handle_failure(dc_dmub_srv);
@@ -146,7 +144,8 @@ void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv,
static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
@@ -162,7 +161,7 @@ static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_s
for (i = 0 ; i < count; i++) {
/* confirm no messages pending */
do {
- status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_idle(dmub, timeout_us);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
/* queue command */
@@ -188,7 +187,8 @@ static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_s
static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
@@ -217,7 +217,7 @@ static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_sr
return false;
do {
- status = dmub_srv_wait_for_inbox_free(dmub, MAX_WAIT_US, count - i);
+ status = dmub_srv_wait_for_inbox_free(dmub, timeout_us, count - i);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
/* Requeue the command. */
@@ -245,17 +245,18 @@ static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_sr
return true;
}
-bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
+bool dc_dmub_srv_cmd_list_queue_execute_timeout(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
bool res = false;
if (dc_dmub_srv && dc_dmub_srv->dmub) {
if (dc_dmub_srv->dmub->inbox_type == DMUB_CMD_INTERFACE_REG) {
- res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
+ res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list, timeout_us);
} else {
- res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
+ res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list, timeout_us);
}
if (res)
@@ -265,9 +266,17 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
return res;
}
+bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
+ unsigned int count,
+ const union dmub_rb_cmd *cmd_list)
+{
+ return dc_dmub_srv_cmd_list_queue_execute_timeout(dc_dmub_srv, count, cmd_list, DMUB_CMD_DEFAULT_MAX_WAIT_US);
+}
+
bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
- union dmub_rb_cmd *cmd_list)
+ union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dmub_srv *dmub;
enum dmub_status status;
@@ -280,7 +289,7 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
// Wait for DMUB to process command
if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) {
do {
- status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_idle(dmub, timeout_us);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
if (status != DMUB_STATUS_OK) {
@@ -314,7 +323,7 @@ bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int coun
if (!dc_dmub_srv_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list))
return false;
- return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list);
+ return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list, DMUB_CMD_DEFAULT_MAX_WAIT_US);
}
bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv)
@@ -1202,9 +1211,16 @@ void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, con
void dc_dmub_srv_cursor_offload_init(struct dc *dc)
{
struct dmub_rb_cmd_cursor_offload_init *init;
- struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
+ struct dc_dmub_srv *dc_dmub_srv;
union dmub_rb_cmd cmd;
+ if (!dc || !dc->ctx)
+ return;
+
+ dc_dmub_srv = dc->ctx->dmub_srv;
+ if (!dc_dmub_srv || !dc_dmub_srv->dmub)
+ return;
+
if (!dc->config.enable_cursor_offload)
return;
@@ -1370,7 +1386,7 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
- dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL);
+ dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL, DMUB_CMD_DEFAULT_MAX_WAIT_US);
memset(&new_signals, 0, sizeof(new_signals));
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
index 5737c78853fc..8056824d90e0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -29,6 +29,8 @@
#include "dm_services_types.h"
#include "dmub/dmub_srv.h"
+#define DMUB_CMD_DEFAULT_MAX_WAIT_US 500000
+
struct dmub_srv;
struct dc;
struct dc_context;
@@ -59,11 +61,17 @@ bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv);
bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list);
+ const union dmub_rb_cmd *cmd_list);
+
+bool dc_dmub_srv_cmd_list_queue_execute_timeout(struct dc_dmub_srv *dc_dmub_srv,
+ unsigned int count,
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us);
bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
- union dmub_rb_cmd *cmd_list);
+ union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us);
bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
new file mode 100644
index 000000000000..904f8c4a4783
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
@@ -0,0 +1,277 @@
+/**
+ * Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * You may not use this software and documentation (if any) (collectively, the
+ * "Materials") except in compliance with the terms and conditions of the
+ * Software License Agreement included with the Materials or otherwise as set
+ * forth in writing and signed by you and an authorized signatory of AMD.
+ *
+ * If you do not have a copy of the Software License Agreement, contact your AMD
+ * representative for a copy. You agree that you will not reverse engineer or
+ * decompile the Materials, in whole or in part, except as allowed by applicable
+ * law.
+ *
+ * THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ */
+#include "dc_memory_pool.h"
+
+#include <linux/atomic.h>
+
+enum {
+ DC_MEMORY_POOL_SENTINEL = -1,
+ DC_MEMORY_POOL_ACQUIRED = -2,
+ DC_MEMORY_POOL_RELEASED = -3,
+
+ // Correct autoincrement for negative numbers
+ DC_MEMORY_POOL_ENUM_SIZE_IMPL,
+ DC_MEMORY_POOL_ENUM_SIZE = 1 - DC_MEMORY_POOL_ENUM_SIZE_IMPL,
+};
+
+// Align everything to size of page to avoid false sharing
+struct dc_memory_pool_page {
+ __aligned(PAGE_SIZE) char _dummy[PAGE_SIZE];
+};
+
+// Generation counter protects against ABA-problem
+union index_t {
+ struct {
+ int32_t value;
+ uint32_t generation;
+ } s;
+
+ int64_t raw;
+};
+
+struct dc_memory_pool {
+ // Values and pointers constant after initialization, can share page
+ __aligned(PAGE_SIZE) size_t size;
+ size_t capacity;
+
+ void *unaligned_pool;
+ void *unaligned_memory;
+ struct dc_memory_pool_page *memory;
+ atomic_t *free_list;
+
+ // Updated every operation, use separate page to avoid false sharing
+ __aligned(PAGE_SIZE) atomic64_t free_head; // index_t
+ char _reserved2[PAGE_SIZE - sizeof(atomic64_t)];
+};
+
+static_assert(sizeof(struct dc_memory_pool) == 2 * PAGE_SIZE);
+static_assert(offsetof(struct dc_memory_pool, free_head) == PAGE_SIZE);
+
+static size_t divide_ceiling(size_t x, size_t d)
+{
+ return (x + d - 1) / d;
+}
+
+static size_t round_up_to_multiple(size_t x, size_t m)
+{
+ return divide_ceiling(x, m) * m;
+}
+
+static size_t size_in_pages(size_t x)
+{
+ return divide_ceiling(x, PAGE_SIZE);
+}
+
+static void *page_align_up(void *p)
+{
+ intptr_t i = (intptr_t)p;
+
+ i = (intptr_t)round_up_to_multiple((size_t)i, PAGE_SIZE);
+ return (void *)i;
+}
+
+__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
+ size_t capacity)
+{
+ if (!size || !capacity)
+ return NULL;
+
+ // Limited by split between size and generation in index_t
+ if (capacity >= (uint32_t)-DC_MEMORY_POOL_ENUM_SIZE)
+ return NULL;
+
+ // uint32_t because that's what alloc functions take
+ const uint32_t block_pages = (uint32_t)size_in_pages(size);
+ const uint32_t lines = (uint32_t)capacity * block_pages;
+ const uint32_t padded_struct_size =
+ sizeof(struct dc_memory_pool) + PAGE_SIZE;
+
+ void *unaligned_pool = kzalloc(padded_struct_size, GFP_KERNEL);
+
+ if (!unaligned_pool)
+ return NULL;
+
+ struct dc_memory_pool *pool = page_align_up(unaligned_pool);
+
+ *pool = (struct dc_memory_pool){
+ .size = size,
+ .capacity = capacity,
+ .unaligned_pool = unaligned_pool,
+ .unaligned_memory = kcalloc(lines + 1, PAGE_SIZE, GFP_KERNEL),
+ .free_list = kcalloc((uint32_t)capacity, sizeof(atomic_t),
+ GFP_KERNEL),
+ .free_head = ATOMIC_INIT(0),
+ };
+ pool->memory = page_align_up(pool->unaligned_memory);
+
+ if (!pool->unaligned_memory || !pool->free_list) {
+ dc_memory_pool_destroy(pool);
+ return NULL;
+ }
+
+ for (int32_t i = 0; i < (int32_t)capacity; i++)
+ atomic_set_release(&pool->free_list[i], i + 1);
+
+ atomic_set_release(&pool->free_list[capacity - 1],
+ DC_MEMORY_POOL_SENTINEL);
+
+ return pool;
+}
+
+void dc_memory_pool_destroy(struct dc_memory_pool *pool)
+{
+ if (!pool)
+ return;
+
+ kfree(pool->free_list);
+ kfree(pool->unaligned_memory);
+ kfree(pool->unaligned_pool);
+}
+
+static int32_t dc_memory_pool_get_index(const struct dc_memory_pool *pool,
+ const void *memory)
+{
+ if (!pool || !memory) {
+ ASSERT(false);
+ return DC_MEMORY_POOL_SENTINEL;
+ }
+
+ // Direct pointer arithmetic would be UB if called by false `owns()`
+ if ((uintptr_t)memory < (uintptr_t)pool->memory)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ const uintptr_t distance = (uintptr_t)memory - (uintptr_t)pool->memory;
+ const size_t block_size = size_in_pages(pool->size) * PAGE_SIZE;
+ const size_t i = (size_t)distance / block_size;
+
+ if (distance % (uintptr_t)block_size != 0)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ if (i >= pool->capacity)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ return (int32_t)i;
+}
+
+static void *dc_memory_pool_get_page(const struct dc_memory_pool *pool,
+ int32_t index)
+{
+ if (!pool) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ if (index < 0 || index >= (int32_t)pool->capacity) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ return &pool->memory[(size_t)index * size_in_pages(pool->size)];
+}
+
+__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool)
+{
+ if (!pool) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ // CAS-atomic `out = head; head = head->next;`
+ union index_t old_head = {
+ .raw = atomic64_read_acquire(&pool->free_head),
+ };
+ union index_t new_head = {
+ .raw = 0,
+ };
+ int32_t i = 0;
+
+ do {
+ i = old_head.s.value;
+ if (i == DC_MEMORY_POOL_SENTINEL)
+ return NULL;
+
+ new_head = (union index_t){
+ .s.value = atomic_read_acquire(&pool->free_list[i]),
+ .s.generation = old_head.s.generation + 1,
+ };
+ } while (!atomic64_try_cmpxchg(&pool->free_head, &old_head.raw,
+ new_head.raw));
+
+ atomic_set_release(&pool->free_list[i], DC_MEMORY_POOL_ACQUIRED);
+ return dc_memory_pool_get_page(pool, i);
+}
+
+void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory)
+{
+ if (!dc_memory_pool_owns(pool, memory)) {
+ // Likely acquired in different pool or (racing?) double free
+ ASSERT(false);
+ return;
+ }
+
+ const int32_t i = dc_memory_pool_get_index(pool, memory);
+
+ if (atomic_xchg(&pool->free_list[i], DC_MEMORY_POOL_RELEASED) !=
+ DC_MEMORY_POOL_ACQUIRED) {
+ // Double free from two racing threads, use krefs to sync
+ ASSERT(false);
+ return;
+ }
+
+ // CAS-atomic `in->next = head; head = in;`
+ union index_t old_head = {
+ .raw = atomic64_read_acquire(&pool->free_head),
+ };
+ union index_t new_head = {
+ .raw = 0,
+ };
+
+ do {
+ atomic_set_release(&pool->free_list[i], old_head.s.value);
+ new_head = (union index_t){
+ .s.value = i,
+ .s.generation = old_head.s.generation + 1,
+ };
+ } while (!atomic64_try_cmpxchg(&pool->free_head, &old_head.raw,
+ new_head.raw));
+}
+
+__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
+ const void *memory)
+{
+ const int32_t i = dc_memory_pool_get_index(pool, memory);
+
+ if (i < 0)
+ return false;
+
+ if (atomic_read_acquire(&pool->free_list[i]) != DC_MEMORY_POOL_ACQUIRED)
+ return false;
+
+ return true;
+}
+
+__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool)
+{
+ ASSERT(pool);
+ return pool->size;
+}
+
+__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool)
+{
+ ASSERT(pool);
+ return pool->capacity;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
new file mode 100644
index 000000000000..0ec305813d66
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
@@ -0,0 +1,107 @@
+/**
+ * Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * You may not use this software and documentation (if any) (collectively, the
+ * "Materials") except in compliance with the terms and conditions of the
+ * Software License Agreement included with the Materials or otherwise as set
+ * forth in writing and signed by you and an authorized signatory of AMD.
+ *
+ * If you do not have a copy of the Software License Agreement, contact your AMD
+ * representative for a copy. You agree that you will not reverse engineer or
+ * decompile the Materials, in whole or in part, except as allowed by applicable
+ * law.
+ *
+ * THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ */
+#ifndef DC_MEMORY_POOL_H
+#define DC_MEMORY_POOL_H
+
+#include "os_types.h"
+
+/**
+ * Non-resizable lock-free memory pool with fixed capacity.
+ *
+ * Custom implementation is used over Linux llist, as llist requires external
+ * locking if more than one thread pops from the list.
+ *
+ * Emplace and erase operations do not use any mutexes or spinlocks, which
+ * guarantees forward progress even if another thread
+ * has been suspended in the middle of the call. High contention might result
+ * in multiple internal retries, but will eventually either succeed once other
+ * threads stop actively modifying the pool, or fail if the pool is empty.
+ *
+ * Implemented as Treiber stack using indexed free list and head with generation
+ * counter to solve ABA problem, as each modification of the head increments
+ * the generation, preventing issue of `push(A)` being indistinguishable from
+ * `push(A); { push(B); pop(B); }` to another thread, corrupting data structure.
+ */
+struct dc_memory_pool;
+
+/**
+ * Create dc_memory_pool.
+ *
+ * @param size Non-zero pool block size, all acquires will be of this size.
+ * @param capacity Non-zero number of blocks that can be acquired from the pool.
+ * @return Pointer to the pool if succeeded, null if failed.
+ */
+__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
+ size_t capacity);
+
+/**
+ * Destroy given pool and free all allocated memory, invalidating any pointers.
+ *
+ * This operation is not synchronized, calling any other operation on the pool
+ * while it is being destroyed results in Undefined Behavior.
+ *
+ * @param pool Can be null to support common destruction patterns.
+ */
+void dc_memory_pool_destroy(struct dc_memory_pool *pool);
+
+/**
+ * Acquire single block from pool.
+ *
+ * @param pool Cannot be null.
+ * @return Pointer to block if succeeded, null if empty.
+ */
+__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool);
+
+/**
+ * Release previously acquired block, freeing it for others to acquire.
+ *
+ * @param pool Cannot be null.
+ * @param memory Cannot be null, has to be owned by the pool.
+ */
+void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory);
+
+/**
+ * Check if given memory is owned by the pool to facilitate arenas.
+ *
+ * @warning if (owns(pool, p)) release(pool, p);` pattern is not safe
+ * if used with same `p` from multiple unsynchronized threads.
+ * If multiple owning threads are desired, use krefs to assure single release.
+ *
+ * @param pool Cannot be null.
+ * @param memory Cannot be null.
+ * @return True if the memory was previously acquired from the pool.
+ */
+__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
+ const void *memory);
+
+/**
+ * Get pool block size.
+ *
+ * @param pool Cannot be null.
+ * @return Pool block size as given to dc_memory_pool_create().
+ */
+__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool);
+
+/**
+ * Get pool block count.
+ *
+ * @param pool Cannot be null.
+ * @return Pool block count as given to dc_memory_pool_create().
+ */
+__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool);
+
+#endif // Header guard
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 934ae381e730..fec5e7a84bb9 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -123,6 +123,9 @@ union stream_update_flags {
uint32_t info_frame : 1;
uint32_t dmdata : 1;
uint32_t dither : 1;
+ uint32_t func_shaper : 1;
+ uint32_t lut3d_func : 1;
+ uint32_t reserved : 11; /* adjust when adding new flags */
} bits;
uint32_t raw;
@@ -611,17 +614,6 @@ bool dc_stream_set_gamut_remap(struct dc *dc,
bool dc_stream_program_csc_matrix(struct dc *dc,
struct dc_stream_state *stream);
-struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream,
- bool allocate_one);
-
-void dc_stream_release_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream);
-
-void dc_stream_init_rmcm_3dlut(struct dc *dc);
-
struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream);
void dc_dmub_update_dirty_rect(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
index 13ba7f5ce13e..71ebdd54f8f0 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
@@ -212,6 +212,7 @@ struct dccg *dccg2_create(
base->ctx = ctx;
base->funcs = &dccg2_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
index 5b9ba9a811ea..ee27d7519d2d 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
@@ -82,6 +82,7 @@ struct dccg *dccg201_create(
base->ctx = ctx;
base->funcs = &dccg201_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
index 1f23dfccf07a..d0735022f198 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
@@ -158,6 +158,7 @@ struct dccg *dccg21_create(
base->ctx = ctx;
base->funcs = &dccg21_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
index 9df06df6c7f1..005ca01d7ecc 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
@@ -114,6 +114,7 @@ struct dccg *dccg3_create(
base->ctx = ctx;
base->funcs = &dccg3_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
@@ -139,6 +140,7 @@ struct dccg *dccg30_create(
base->ctx = ctx;
base->funcs = &dccg3_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
index 837f4e3d1a60..022e8d3dfce2 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
@@ -73,6 +73,7 @@ struct dccg *dccg301_create(
base->ctx = ctx;
base->funcs = &dccg301_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
index ce90cba853f7..341509ad6f35 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
@@ -965,6 +965,7 @@ struct dccg *dccg31_create(
base->ctx = ctx;
base->funcs = &dccg31_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
index 1a4d4cd58ad8..a71851779b37 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
@@ -429,6 +429,7 @@ struct dccg *dccg314_create(
base->ctx = ctx;
base->funcs = &dccg314_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
index f75c5aa2d23e..52161c745a48 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
@@ -441,6 +441,7 @@ struct dccg *dccg32_create(
base->ctx = ctx;
base->funcs = &dccg32_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
index 4fbd40b518cd..ba624f442915 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
@@ -2804,6 +2804,7 @@ struct dccg *dccg35_create(
base->ctx = ctx;
base->funcs = &dccg35_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
index 7bff1b9da6f9..a4ece209d600 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
@@ -999,6 +999,7 @@ struct dccg *dccg401_create(
base->ctx = ctx;
base->funcs = &dccg401_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
index 2f498daf8f2b..bdf2bd388be7 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
@@ -382,6 +382,7 @@ struct dccg *dccg42_create(
base->ctx = ctx;
base->funcs = &dccg42_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
index 1d6d193b23c7..e08a9679aaf7 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
@@ -179,6 +179,7 @@ struct dccg *dccg60_create(
base->ctx = ctx;
base->funcs = &dccg60_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
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 20ccecf23677..f88404a37dea 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
@@ -1232,9 +1232,9 @@ static bool get_dp_dto_frequency_100hz(
*/
modulo_hz = REG_READ(MODULO[inst]);
if (modulo_hz) {
- temp = clock_hz * dp_dto_ref_khz * 10;
+ temp = (unsigned long long)clock_hz * dp_dto_ref_khz * 10;
ASSERT(temp <= UINT_MAX * modulo_hz * 100ULL);
- *pixel_clk_100hz = div_u64(temp, modulo_hz * 100);
+ *pixel_clk_100hz = (unsigned int)div_u64(temp, modulo_hz * 100);
} else
*pixel_clk_100hz = 0;
} else {
@@ -1293,7 +1293,7 @@ static bool dcn401_get_dp_dto_frequency_100hz(const struct clock_source *clock_s
BREAK_TO_DEBUGGER();
*pixel_clk_100hz = 0;
} else {
- *pixel_clk_100hz = div_u64(temp, 100);
+ *pixel_clk_100hz = (unsigned int)div_u64(temp, 100);
}
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
index eda3a2f1402c..0785a30eb643 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
@@ -415,6 +415,30 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
+static bool dmub_replay_get_cumulative_residency(struct dmub_replay *dmub,
+ uint8_t panel_inst, uint32_t *residency_milli_pct)
+{
+ uint32_t milli_pct = 0;
+ uint16_t param = (uint16_t)panel_inst;
+
+ if (!residency_milli_pct)
+ return false;
+
+ /* Zero on failure so the caller never reads a stale value, and report
+ * false so a failed query is still distinguishable from a genuine 0%.
+ */
+ *residency_milli_pct = 0;
+
+ if (!dc_wake_and_execute_gpint(dmub->ctx,
+ DMUB_GPINT__REPLAY_SNAPSHOT_CUMULATIVE_RESIDENCY,
+ param, &milli_pct, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
+ return false;
+
+ *residency_milli_pct = milli_pct;
+
+ return true;
+}
+
static const struct dmub_replay_funcs replay_funcs = {
.replay_copy_settings = dmub_replay_copy_settings,
.replay_enable = dmub_replay_enable,
@@ -424,6 +448,7 @@ static const struct dmub_replay_funcs replay_funcs = {
.replay_residency = dmub_replay_residency,
.replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal,
.replay_send_cmd = dmub_replay_send_cmd,
+ .replay_get_cumulative_residency = dmub_replay_get_cumulative_residency,
};
/*
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
index 07c79739a980..271a42a226e9 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
@@ -33,6 +33,8 @@ struct dmub_replay_funcs {
void (*replay_set_power_opt_and_coasting_vtotal)(struct dmub_replay *dmub,
unsigned int power_opt, uint8_t panel_inst, uint32_t coasting_vtotal,
uint16_t frame_skip_number);
+ bool (*replay_get_cumulative_residency)(struct dmub_replay *dmub,
+ uint8_t panel_inst, uint32_t *residency_milli_pct);
};
struct dmub_replay *dmub_replay_create(struct dc_context *ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c
index 5bc3bc60a2ac..ebbe7900205e 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c
@@ -46,7 +46,7 @@ static void dcn20_wait_for_vmid_ready(struct dcn20_vmid *vmid)
/* According the hardware spec, we need to poll for the lowest
* bit of PAGE_TABLE_BASE_ADDR_LO32 = 1 any time a GPUVM
* context is updated. We can't use REG_WAIT here since we
- * don't have a seperate field to wait on.
+ * don't have a separate field to wait on.
*
* TODO: Confirm timeout / poll interval with hardware team
*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
index 0f8666788bbb..e83a9ac018db 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
@@ -202,7 +202,7 @@ static const struct dml2_soc_bb dml2_socbb_dcn42b = {
.xtalclk_mhz = 24,
.pcie_refclk_mhz = 100,
.dchub_refclk_mhz = 50,
- .mall_allocated_for_dcn_mbytes = 64,
+ .mall_allocated_for_dcn_mbytes = 0,
.max_outstanding_reqs = 256,
.fabric_datapath_to_dcn_data_return_bytes = 32,
.return_bus_width_bytes = 64,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index 47d63dd69a90..64afb67054d5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -2001,6 +2001,10 @@ static void CalculateMALLUseForStaticScreen(
#endif
}
+ /* If no MALL is allocated for DCN, there is no need to calculate usage for static screen. */
+ if (MALLAllocatedForDCN == 0)
+ return;
+
SurfaceToAddToMALL = 0;
CanAddAnotherSurfaceToMALL = true;
while (CanAddAnotherSurfaceToMALL) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
index 7ae02eccd598..de078ccd91a2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
@@ -887,6 +887,7 @@ bool pmo_dcn4_fams2_optimize_for_vmin(struct dml2_pmo_optimize_for_vmin_in_out *
const struct dml2_core_mode_support_result *mode_support_result =
&in_out->base_display_config->mode_support_result;
unsigned int odms_used;
+ int odm_combine_limit;
struct dml2_stream_parameters *stream_descriptor;
bool optimizable = false;
@@ -901,8 +902,16 @@ bool pmo_dcn4_fams2_optimize_for_vmin(struct dml2_pmo_optimize_for_vmin_in_out *
in_out->base_display_config->stage4.unoptimizable_streams[stream_index])
return false;
+ /*
+ * Enforce a max cap on ODM combine factor of 2:1 for eDP stream
+ */
+ odm_combine_limit = in_out->instance->odm_combine_limit;
+ if (display_config->stream_descriptors[stream_index].output.output_encoder == dml2_edp &&
+ odm_combine_limit > 2)
+ odm_combine_limit = 2;
+
odms_used = mode_support_result->cfg_support_info.stream_support_info[stream_index].odms_used;
- if ((int)odms_used >= in_out->instance->odm_combine_limit)
+ if ((int)odms_used >= odm_combine_limit)
return false;
memcpy(in_out->optimized_display_config,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
index 73e02b10934f..77c9308bb9e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
@@ -290,7 +290,7 @@ static bool dml2_top_utm_check_mode_supported(struct dml2_check_mode_supported_i
DML_LOG_INFO("%s exit with %s\n", __func__, dml2_status_str(status));
DML_LOG_TOP_IF_EXIT();
- return true;
+ return status == DML2_STATUS_OK;
}
static bool dml2_top_utm_build_mode_programming(struct dml2_build_mode_programming_in_out *in_out)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
index 3c25de54d55b..366767f4413e 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
@@ -39,6 +39,7 @@ static void dml21_populate_pmo_options(struct dml2_pmo_options *pmo_options,
pmo_options->disable_drr_clamped_when_var_active = in_dc->debug.disable_fams_gaming == INGAME_FAMS_DISABLE;
pmo_options->force_mandatory_uclk_pstate_support = config->pmo.force_mandatory_uclk_pstate_support;
+ pmo_options->force_optional_uclk_pstate_support = in_dc->debug.force_optional_uclk_pstate_support;
}
static enum dml2_project_id dml21_dcn_revision_to_dml2_project_id(const struct dc *in_dc)
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
index 8fe3474411b7..083ab6acb687 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
@@ -1,6 +1,8 @@
/*
* Copyright 2020 Advanced Micro Devices, Inc.
*
+ * SPDX-License-Identifier: MIT
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
index 04cab7d3a5c2..38739ed048fa 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
@@ -25,17 +25,27 @@
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling)
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear)
{
struct dcn50_dpp *dpp = TO_DCN50_DPP(dpp_base);
enum pregam_mode pre_degam_en = PREGAM_DEGAM;
enum degam_lut degamma_lut_selection = 0;
if (scaling == DC_SCALING_LINEARITY_SOURCE) {
- //If scaling in non-linear, apply regamma
- REG_SET_2(PRE_GAM, 0,
- PRE_GAM_MODE, PREGAM_REGAM,
- PRE_REGAM_SELECT, REGAM_20);
+ if (source_is_linear) {
+ //Linear source data (e.g. FP16) must be de-linearized
+ //(apply regamma) before scaling in source/non-linear space.
+ REG_SET_2(PRE_GAM, 0,
+ PRE_GAM_MODE, PREGAM_REGAM,
+ PRE_REGAM_SELECT, REGAM_20);
+ } else {
+ //Non-linear source data (e.g. YUV) is already in source
+ //space, so scale directly with no pregam conversion.
+ REG_SET_2(PRE_GAM, 0,
+ PRE_GAM_MODE, PREGAM_BYPASS,
+ PRE_DEGAM_SELECT, 0);
+ }
} else {
//If scaling in linear, apply degamma based on TF
switch (tr) {
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
index 7f5d3fa6bbef..c81e910ae095 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
@@ -82,6 +82,7 @@ void dpp50_dpp_setup(
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling);
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear);
#endif /* __DCN50_DPP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
index cff5c95a771c..f4c21998d845 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
@@ -921,9 +921,9 @@ void hpo_enc3_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state)
{
- int pixel_encoding;
- int color_depth;
- int odm_combine;
+ uint32_t pixel_encoding;
+ uint32_t color_depth;
+ uint32_t odm_combine;
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT(state);
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
index d4f66e62c729..43870d84ca2f 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
@@ -159,11 +159,16 @@ void hpo_enc42_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
+ struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT (enc->apg);
- if (mute)
+
+ if (mute) {
enc->apg->funcs->disable_apg(enc->apg);
- else
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 0);
+ } else {
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
enc->apg->funcs->enable_apg(enc->apg);
+ }
}
static const struct hpo_frl_stream_encoder_funcs dcn42_str_enc_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
index bded65896ef5..b5397d6760b1 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
@@ -36,11 +36,16 @@ static void hpo_enc60_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
+ struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT (enc->apg);
- if (mute)
+
+ if (mute) {
enc->apg->funcs->disable_apg(enc->apg);
- else
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 0);
+ } else {
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
enc->apg->funcs->enable_apg(enc->apg);
+ }
}
//Covered both, rounding up or rounding down from FRL Link Rate /18.
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
index cbcd22789013..35c94ca8335a 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
@@ -1048,11 +1048,6 @@ void hubbub31_init(struct hubbub *hubbub)
DISPCLK_R_DCHUBBUB_GATE_DIS, 1,
DCFCLK_R_DCHUBBUB_GATE_DIS, 1);
}
-
- /*
- only the DCN will determine when to connect the SDP port
- */
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, 1);
}
static const struct hubbub_funcs hubbub31_funcs = {
.update_dchub = hubbub2_update_dchub,
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
index 53744b000f5d..466bab437e37 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
@@ -531,12 +531,7 @@ void hubbub35_init(struct hubbub *hubbub)
hubbub35_set_fgcg(hubbub2,
hubbub->ctx->dc->debug.enable_fine_grain_clock_gating
.bits.dchubbub);
- /*
- ignore the "df_pre_cstate_req" from the SDP port control.
- only the DCN will determine when to connect the SDP port
- */
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
- SDPIF_PORT_CONTROL, 1);
+
/*Set SDP's max outstanding request
When set to 1: Max outstanding is 512
When set to 0: Max outstanding is 256
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
index ddfc60e845a4..71bc926c7035 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
@@ -431,13 +431,6 @@ static void hubbub42_allow_self_refresh_control(struct hubbub *hubbub, bool allo
DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow);
}
-static void hubbub42_set_sdp_control(struct hubbub *hubbub, bool dc_control)
-{
- struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
-
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
- SDPIF_PORT_CONTROL, dc_control);
-}
static bool hubbub42_program_watermarks(
struct hubbub *hubbub,
@@ -449,9 +442,8 @@ static bool hubbub42_program_watermarks(
struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
if (!safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
- /* before raising watermarks, SDP control give to DF, stutter must be disabled */
+ /* before raising watermarks, stutter must be disabled */
wm_pending = true;
- hubbub42_set_sdp_control(hubbub, false);
hubbub42_allow_self_refresh_control(hubbub, false);
}
if (hubbub42_program_urgent_watermarks(hubbub, watermarks, safe_to_lower))
@@ -478,9 +470,6 @@ static bool hubbub42_program_watermarks(
if (safe_to_lower || hubbub->ctx->dc->debug.disable_stutter)
hubbub42_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
- if (safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
- hubbub42_set_sdp_control(hubbub, true);
- }
hubbub32_force_usr_retraining_allow(hubbub, hubbub->ctx->dc->debug.force_usr_allow);
return wm_pending;
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
index 0169ffcd9343..c89c8ff42185 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
@@ -742,9 +742,19 @@ static void hubbub60_wm_read_state(struct hubbub *hubbub,
static void hubbub60_perfmon_reset(struct hubbub *hubbub)
{
struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+ unsigned int counter;
REG_WRITE(DC_PERFMON5_PERFMON_CNTL, 0);
REG_WRITE(DC_PERFMON5_PERFMON_CNTL2, 0);
+
+ for (counter = 0; counter < 8; counter++) {
+ REG_SET_2(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ PERFCOUNTER_CNTL_SEL, counter,
+ PERFCOUNTER_OFF_MASK, 0x1);
+ REG_SET(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
+ PERFCOUNTER_CNTL2_SEL, counter);
+ }
+
REG_WRITE(DC_PERFMON5_PERFCOUNTER_STATE, 0);
REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, 0xFF00);
REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_LOW, 0);
@@ -1381,7 +1391,7 @@ static uint32_t hubbub60_perfmon_get_urgent_ramp_latency_ns(
* Counter 1: data counter — tracks total data received during the measurement
* period.
* Counter 2: target-reached generator — duplicates counter 1's event/target
- * and generates the interrupt that stops counters 1 and 4.
+ * and generates the counter-off event that stops counters 1 and 4.
* Counter 4: duration timer — measures elapsed time in refclk cycles.
*
* UTM_FILTER_SEL is set to 0 so that isolation comes from OTG-vblank gating
@@ -1396,7 +1406,7 @@ static uint32_t hubbub60_perfmon_get_urgent_ramp_latency_ns(
* windbg (ed dcn60_debug_peak_bw_ramp_size / ed dcn60_debug_peak_bw_window_size).
*/
static unsigned int dcn60_debug_peak_bw_ramp_size = 0x100;
-static unsigned int dcn60_debug_peak_bw_window_size = 0x2500;
+static unsigned int dcn60_debug_peak_bw_window_size = 5000;
/* Minimum count4 (refclk ticks) for a peak-BW sample to be trusted. */
#define DCN60_OUT_OF_ORDER_BW_MIN_DURATION_TICKS 20
@@ -1419,7 +1429,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
UTM_FILTER_SEL, 0x0);
/* Program counter 0 as the count off counter */
- REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x1, // use cvalue bits 15-0
@@ -1427,7 +1437,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x0, // simutaneous mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_ACTIVE, 1);
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
+ PERFCOUNTER_ACTIVE, 0x1);
REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0
PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value
@@ -1436,7 +1447,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
/* Program counter 1 as a passive data accumulator, slaved to the same
* external stop signal as counter 4 (generated by counter 2 below). */
- REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_10(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x1, // select counter 1
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x2, // use cvalue bits 31-16
@@ -1444,7 +1455,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_INT_EN, 0, // counter 2 now generates the interrupt
+ PERFCOUNTER_INT_EN, 0, // counter 2 is the completion source
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
PERFCOUNTER_ACTIVE, 0x1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x1,
@@ -1454,9 +1466,9 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_STOP2_SEL, 0x1); // stop via the same external signal as counter 4
/* Counter 2 is a dedicated "target reached" generator: it duplicates
- * counter 1's event/target and is the sole source of the completion
- * interrupt driving PERFMON_RUN_ENABLE_STOP_SEL. */
- REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ * counter 1's event/target and is the sole source of the counter-off
+ * event driving PERFMON_RUN_ENABLE_STOP_SEL. */
+ REG_SET_10(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x2, // select counter 2
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x2, // use cvalue bits 31-16 (same window target as counter 1)
@@ -1464,7 +1476,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_INT_EN, 1, // signal when the measurement is complete
+ PERFCOUNTER_INT_EN, 0, // counter-off is the completion source
+ PERFCOUNTER_OFF_MASK, 0x0, // generate pmon_counter_off_out at CVALUE
PERFCOUNTER_ACTIVE, 0x1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x2,
@@ -1474,7 +1487,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_STOP2_SEL, 0x0); // the stop trigger is that perfcounter meet the target CVALUE
/* Program counter 4 to count the measuring time */
- REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x4, // select counter 4
PERFCOUNTER_EVENT_SEL, 19, // always 1 event
PERFCOUNTER_CVALUE_SEL, 0x0, // ignored
@@ -1482,6 +1495,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
PERFCOUNTER_ACTIVE, 1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x4, // select counter 4
@@ -1509,7 +1523,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
REG_SET_2(DC_PERFMON5_PERFMON_CNTL2, 0,
PERFMON_RUN_ENABLE_START_SEL, 0x0,
- PERFMON_RUN_ENABLE_STOP_SEL, 11); // perfmon counter off event
+ PERFMON_RUN_ENABLE_STOP_SEL, 10); // stop on counter-off event
}
/**
@@ -1517,9 +1531,9 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
* @hubbub: pointer to the hubbub hardware instance
*
* Enables the performance monitor counters previously configured by
- * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(). The counter
- * self-stops once the count-off counter reaches its target; there is no
- * explicit stop step for the peak-BW path.
+ * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(). Counter 2 stops
+ * the measurement once it reaches its target; there is no explicit stop
+ * step for the peak-BW path.
*/
static void hubbub60_perfmon_start_measuring_out_of_order_bandwidth(
struct hubbub *hubbub)
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
index d8eb5996b577..2a4be0c7a724 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
@@ -350,10 +350,12 @@ 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,
+ bool dcc)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+ (void)dcc;
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
index f2571076fc50..0c1d5e518f97 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
@@ -905,7 +905,8 @@ void hubp_reset(struct hubp *hubp);
bool hubp1_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
bool hubp1_is_flip_pending(struct hubp *hubp);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
index cf2c9f80056e..79a429814061 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
@@ -730,10 +730,13 @@ bool hubp2_dmdata_status_done(struct hubp *hubp)
bool hubp2_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
index ea90dee05d5f..3ae06bf89f79 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
@@ -399,7 +399,8 @@ void hubp2_program_deadline(
bool hubp2_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp2_dcc_control(struct hubp *hubp, bool enable,
enum hubp_ind_block_size independent_64b_blks);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
index 0dba8ff8a19d..c667db319baf 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
@@ -696,10 +696,13 @@ static void dmcub_PLAT_54186_wa(struct hubp *hubp,
static bool hubp21_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct surface_flip_registers flip_regs = { 0 };
+ (void)dcc;
+
flip_regs.vmid = address->vmid;
switch (address->type) {
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
index 4f5f10f6d1cc..72698b5cf5f7 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
@@ -68,10 +68,13 @@ void hubp3_set_vm_system_aperture_settings(struct hubp *hubp,
bool hubp3_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
index c767e9f4f9b3..faa7e0379f4e 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
@@ -260,7 +260,8 @@ void hubp3_set_vm_system_aperture_settings(struct hubp *hubp,
bool hubp3_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp3_program_surface_config(
struct hubp *hubp,
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
index a2e0bafb711a..5ca40941c355 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
@@ -126,6 +126,10 @@ static enum hubp_3dlut_fl_width hubp401_get_3dlut_fl_width(
enum hubp_3dlut_fl_width width = 0;
switch (size) {
+ case CM_LUT_SIZE_999:
+ ASSERT(swizzle != CM_LUT_1D_PACKED_LINEAR);
+ width = hubp_3dlut_fl_width_9;
+ break;
case CM_LUT_SIZE_333333:
ASSERT(swizzle != CM_LUT_1D_PACKED_LINEAR);
width = hubp_3dlut_fl_width_33;
@@ -482,10 +486,13 @@ void hubp401_setup_interdependent(
bool hubp401_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
index adf343837652..818cea479272 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
@@ -271,7 +271,8 @@ void hubp401_setup_interdependent(
bool hubp401_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp401_dcc_control(struct hubp *hubp,
struct dc_plane_dcc_param *dcc);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
index 86e49eb84a54..0c8a23cef1e0 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
@@ -398,10 +398,13 @@ void hubp42_program_3dlut_fl_config(struct hubp *hubp,
static bool hubp42_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
@@ -732,7 +735,6 @@ struct hubp_funcs dcn42_hubp_funcs = {
.hubp_program_3dlut_fl_crossbar = hubp42_program_3dlut_fl_crossbar,
.hubp_get_3dlut_fl_done = hubp401_get_3dlut_fl_done,
.hubp_clear_tiling = hubp3_clear_tiling,
- .hubp_program_3dlut_fl_config = hubp401_program_3dlut_fl_config,
.hubp_read_reg_state = hubp3_read_reg_state
};
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
index 0230f03590cf..ba86e30b1180 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
@@ -22,7 +22,8 @@
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
@@ -55,8 +56,10 @@ bool hubp50_program_surface_flip_and_addr(
if (address->grph.addr.quad_part == 0)
break;
- REG_UPDATE(DCSURF_SURFACE_CONTROL,
- PRIMARY_SURFACE_TMZ, address->tmz_surface);
+ REG_UPDATE_3(DCSURF_SURFACE_CONTROL,
+ PRIMARY_SURFACE_TMZ, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
@@ -71,9 +74,11 @@ bool hubp50_program_surface_flip_and_addr(
|| address->video_progressive.chroma_addr.quad_part == 0)
break;
- REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
- PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
+ PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
@@ -96,11 +101,13 @@ bool hubp50_program_surface_flip_and_addr(
|| address->grph_stereo.right_addr.quad_part == 0)
break;
- REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_6(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
SECONDARY_SURFACE_TMZ, address->tmz_surface,
- SECONDARY_SURFACE_TMZ_C, address->tmz_surface);
+ SECONDARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, 0,
SECONDARY_SURFACE_ADDRESS_HIGH_C,
@@ -139,9 +146,11 @@ bool hubp50_program_surface_flip_and_addr(
|| address->rgbea.alpha_addr.quad_part == 0)
break;
- REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
- PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
+ PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
@@ -457,7 +466,6 @@ void hubp50_program_surface_config(
(void)compat_level;
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
- hubp401_dcc_control(hubp, dcc);
hubp50_program_tiling(hubp2, tiling_info, format);
hubp401_program_size(hubp, format, plane_size, dcc);
hubp2_program_rotation(hubp, rotation, horizontal_mirror);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
index e7d9bb3623b9..a497a90947b6 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
@@ -21,7 +21,8 @@
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp50_program_surface_config(
struct hubp *hubp,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 1b0fc0853045..84e146f2509c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -41,6 +41,7 @@
#include "opp.h"
#include "ipp.h"
#include "mpc.h"
+#include "rmcm.h"
#include "reg_helper.h"
#include "dcn10/dcn10_hubp.h"
#include "dcn10/dcn10_hubbub.h"
@@ -565,31 +566,32 @@ static void dcn10_log_color_state(struct dc *dc,
"OUT_OFFSET", "OUT_SCALE", "FL_DONE", "SOFT_UNDERFLOW", "HARD_UNDERFLOW",
"MEM_PWR_ST", "FORCE", "DIS", "MODE"};
- for (i = 0; i < pool->mpcc_count; i++) {
- struct mpcc_state s = {0};
+ /* Read RMCM state separately - RMCM is a shared resource (only 2 instances) */
+ for (i = 0; i < MAX_RMCM_INST && i < pool->mpcc_count; i++) {
+ struct rmcm_state r = {0};
- pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
- if (s.opp_id != 0xf) {
+ if (pool->rmcm[i] && pool->rmcm[i]->funcs->read_rmcm_state) {
+ pool->rmcm[i]->funcs->read_rmcm_state(pool->rmcm[i], i, &r);
uint32_t values[] = {
i,
- s.rmcm_regs.rmcm_3dlut_size,
- s.rmcm_regs.rmcm_3dlut_mode,
- s.rmcm_regs.rmcm_3dlut_mode_cur,
- s.rmcm_regs.rmcm_3dlut_read_sel,
- s.rmcm_regs.rmcm_3dlut_30bit_en,
- s.rmcm_regs.rmcm_3dlut_wr_en_mask,
- s.rmcm_regs.rmcm_3dlut_ram_sel,
- s.rmcm_regs.rmcm_3dlut_out_norm_factor,
- s.rmcm_regs.rmcm_3dlut_fl_sel,
- s.rmcm_regs.rmcm_3dlut_out_offset_r,
- s.rmcm_regs.rmcm_3dlut_out_scale_r,
- s.rmcm_regs.rmcm_3dlut_fl_done,
- s.rmcm_regs.rmcm_3dlut_fl_soft_underflow,
- s.rmcm_regs.rmcm_3dlut_fl_hard_underflow,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_state,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_force,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_dis,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_mode};
+ r.regs.rmcm_3dlut_size,
+ r.regs.rmcm_3dlut_mode,
+ r.regs.rmcm_3dlut_mode_cur,
+ r.regs.rmcm_3dlut_read_sel,
+ r.regs.rmcm_3dlut_30bit_en,
+ r.regs.rmcm_3dlut_wr_en_mask,
+ r.regs.rmcm_3dlut_ram_sel,
+ r.regs.rmcm_3dlut_out_norm_factor,
+ r.regs.rmcm_3dlut_fl_sel,
+ r.regs.rmcm_3dlut_out_offset_r,
+ r.regs.rmcm_3dlut_out_scale_r,
+ r.regs.rmcm_3dlut_fl_done,
+ r.regs.rmcm_3dlut_fl_soft_underflow,
+ r.regs.rmcm_3dlut_fl_hard_underflow,
+ r.regs.rmcm_3dlut_mem_pwr_state,
+ r.regs.rmcm_3dlut_mem_pwr_force,
+ r.regs.rmcm_3dlut_mem_pwr_dis,
+ r.regs.rmcm_3dlut_mem_pwr_mode};
int num_elements = 19;
@@ -600,17 +602,18 @@ static void dcn10_log_color_state(struct dc *dc,
DTN_INFO("\n");
DTN_INFO("===== MPC RMCM Shaper =====\n");
DTN_INFO("MPCC: CNTL LUT_MODE MODE_CUR WR_EN_MASK WR_SEL OFFSET SCALE START_B START_SEG_B END_B END_BASE_B MEM_PWR_ST FORCE DIS MODE\n");
- for (i = 0; i < pool->mpcc_count; i++) {
- struct mpcc_state s = {0};
+ for (i = 0; i < MAX_RMCM_INST && i < pool->mpcc_count; i++) {
+ struct rmcm_state r = {0};
- pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
- if (s.opp_id != 0xf)
+ if (pool->rmcm[i] && pool->rmcm[i]->funcs->read_rmcm_state) {
+ pool->rmcm[i]->funcs->read_rmcm_state(pool->rmcm[i], i, &r);
DTN_INFO("[%2d]: %4xh %4xh %6xh %4x %4x %4x %4x %4x %4xh %4xh %6xh %4x %4x %4x %4x\n",
- i, s.rmcm_regs.rmcm_cntl, s.rmcm_regs.rmcm_shaper_lut_mode, s.rmcm_regs.rmcm_shaper_mode_cur,
- s.rmcm_regs.rmcm_shaper_lut_write_en_mask, s.rmcm_regs.rmcm_shaper_lut_write_sel, s.rmcm_regs.rmcm_shaper_offset_b,
- s.rmcm_regs.rmcm_shaper_scale_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_seg_b,
- s.rmcm_regs.rmcm_shaper_rama_exp_region_end_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_end_base_b, s.rmcm_regs.rmcm_shaper_mem_pwr_state,
- s.rmcm_regs.rmcm_shaper_mem_pwr_force, s.rmcm_regs.rmcm_shaper_mem_pwr_dis, s.rmcm_regs.rmcm_shaper_mem_pwr_mode);
+ i, r.regs.rmcm_cntl, r.regs.rmcm_shaper_lut_mode, r.regs.rmcm_shaper_mode_cur,
+ r.regs.rmcm_shaper_lut_write_en_mask, r.regs.rmcm_shaper_lut_write_sel, r.regs.rmcm_shaper_offset_b,
+ r.regs.rmcm_shaper_scale_b, r.regs.rmcm_shaper_rama_exp_region_start_b, r.regs.rmcm_shaper_rama_exp_region_start_seg_b,
+ r.regs.rmcm_shaper_rama_exp_region_end_b, r.regs.rmcm_shaper_rama_exp_region_end_base_b, r.regs.rmcm_shaper_mem_pwr_state,
+ r.regs.rmcm_shaper_mem_pwr_force, r.regs.rmcm_shaper_mem_pwr_dis, r.regs.rmcm_shaper_mem_pwr_mode);
+ }
}
}
@@ -1747,7 +1750,9 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
if (tg->funcs->is_tg_enabled(tg)) {
if (tg->funcs->init_odm)
- tg->funcs->init_odm(tg);
+ if (!tg->funcs->is_odm_enabled ||
+ !tg->funcs->is_odm_enabled(tg))
+ tg->funcs->init_odm(tg);
}
tg->funcs->tg_init(tg);
@@ -2057,7 +2062,8 @@ static bool patch_address_for_sbs_tb_stereo(
return false;
}
-void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn10_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
(void)dc;
bool addr_patched = false;
@@ -2069,10 +2075,8 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &plane_state->address,
- plane_state->flip_immediate);
+ *addr_to_program = plane_state->address;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -2083,6 +2087,23 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn10_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
+}
+
bool dcn10_set_input_transfer_func(struct set_input_transfer_func_params *params)
{
struct dpp *dpp = params->dpp;
@@ -3145,8 +3166,14 @@ static void dcn10_update_dchubp_dpp(
}
if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
@@ -4158,5 +4185,6 @@ void dcn10_reset_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
/* force page flip to see the new content of the framebuffer */
hubp->funcs->hubp_program_surface_flip_and_addr(hubp,
&plane_state->address,
- true);
+ true,
+ plane_state->dcc.enable);
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
index 30c213f2e8d6..5cb109040d3d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
@@ -73,6 +73,8 @@ void dcn10_program_output_csc(struct dc *dc,
bool dcn10_set_output_transfer_func(struct set_output_transfer_func_params *params);
bool dcn10_set_input_transfer_func(struct set_input_transfer_func_params *params);
void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn10_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
void dcn10_reset_hw_ctx_wrap(
struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
index 47ab50a3fab1..07e92742c11a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
@@ -39,6 +39,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.post_unlock_program_front_end = dcn10_post_unlock_program_front_end,
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.update_plane_addr = dcn10_update_plane_addr,
+ .prepare_plane_addr_update = dcn10_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 1e60b852e61f..e5f266b0013d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -719,6 +719,10 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
+ /* Clearing 3DLUT fast load writes to HUBP, so it must precede hubp_clk_cntl() below */
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(dc, pipe_ctx->plane_res.rmcm, hubp, pipe_ctx->plane_res.mpcc_inst);
+
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
/* In flip immediate with pipe splitting case GSL is used for
@@ -1834,8 +1838,14 @@ void dcn20_update_dchubp_dpp(
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
@@ -2767,7 +2777,8 @@ static bool patch_address_for_sbs_tb_stereo(
return false;
}
-void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn20_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
bool addr_patched = false;
PHYSICAL_ADDRESS_LOC addr;
@@ -2782,10 +2793,8 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid,
(uint8_t)pipe_ctx->plane_res.hubp->inst);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &plane_state->address,
- plane_state->flip_immediate);
+ *addr_to_program = plane_state->address;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -2796,6 +2805,23 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn20_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
+}
+
void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings)
{
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
index c7bf79fda54c..9711b8bc9083 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
@@ -41,6 +41,8 @@ void dcn20_post_unlock_program_front_end(
struct dc *dc,
struct dc_state *context);
void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn20_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
bool dcn20_set_input_transfer_func(struct set_input_transfer_func_params *params);
bool dcn20_set_output_transfer_func(struct set_output_transfer_func_params *params);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
index 1c6c4e19bdda..c4de9cf11c23 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
@@ -40,6 +40,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
index 9f4bc2a49873..c22587188c98 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
@@ -133,7 +133,8 @@ static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
}
}
-void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn201_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
bool addr_patched = false;
PHYSICAL_ADDRESS_LOC addr;
@@ -149,10 +150,9 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
plane_address_in_gpu_space_to_uma(hws, &uma);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &uma,
- plane_state->flip_immediate);
+ /* snapshot the UMA-converted address before the stereo patch is restored */
+ *addr_to_program = uma;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -163,6 +163,23 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn201_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
+}
+
/* Blank pixel data during initialization */
void dcn201_init_blank(
struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
index bab5d9e6912e..dbcaa0a3a02c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
@@ -33,6 +33,8 @@ void dcn201_init_hw(struct dc *dc);
void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings);
void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn201_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
void dcn201_plane_atomic_disconnect(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx);
void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
index 95dda06b6b17..be1fb2366c8a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn10_post_unlock_program_front_end,
.update_plane_addr = dcn201_update_plane_addr,
+ .prepare_plane_addr_update = dcn201_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
index b8ed664e1bab..20c6e7d7c897 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 8b0a667dc59b..79f40b483caf 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -1065,10 +1065,12 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
*/
unsigned int denom = refresh_hz * 6528;
unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
+ uint64_t num = (1000000LL + 2 * stutter_period * refresh_hz) *
+ (100LL + dc->debug.mall_additional_timer_percent);
+ uint64_t tmr_ticks;
- tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
- (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
- denom) - 64LL);
+ tmr_ticks = div_u64(num + denom - 1, denom);
+ tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
/* In some cases the stutter period is really big (tiny modes) in these
* cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
@@ -1090,9 +1092,8 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
}
denom *= 2;
- tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
- (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
- denom) - 64LL);
+ tmr_ticks = div_u64(num + denom - 1, denom);
+ tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
}
/* Copy HW cursor */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
index b655c01f013b..f62f1c6efff8 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
index dfacc59166cd..a62434138eca 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
@@ -43,6 +43,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
index 3c2e2162da11..30ad41d08d6e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
@@ -44,6 +44,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
index b50ab468b8f8..a53e7fb6f23f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
@@ -46,6 +46,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
index 79be5c385280..5de38b86cb54 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
@@ -528,6 +528,24 @@ bool dcn32_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
return result;
}
+/*
+ * FP16 / 64bpp 16161616 surfaces store pixel data in linear light. These are
+ * the only source formats that must be de-linearized before scaling in
+ * source/non-linear space; every other format is already non-linear.
+ */
+static bool is_source_pixel_format_linear(enum surface_pixel_format format)
+{
+ switch (format) {
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params)
{
struct dce_hwseq *hws = params->dc->hwseq;
@@ -547,7 +565,8 @@ bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params
tf = plane_state->in_transfer_func.tf;
if (dpp->funcs->dpp_set_pregam_state)
- dpp->funcs->dpp_set_pregam_state(dpp, tf, plane_state->scaling_linearity);
+ dpp->funcs->dpp_set_pregam_state(dpp, tf, plane_state->scaling_linearity,
+ is_source_pixel_format_linear(plane_state->format));
else
dpp->funcs->dpp_set_pre_degam(dpp, tf);
@@ -560,10 +579,24 @@ bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params
dpp->funcs->dpp_program_gamcor_lut(dpp, pwl_params);
- if (hws->funcs.set_mcm_luts)
- result = hws->funcs.set_mcm_luts(params->dc, dpp, params->hubp,
- params->primary_hubp, params->mpc, params->mpcc_id,
- params->stream, plane_state);
+ /* MCM and RMCM are mutually exclusive - tear the inactive one out before programming
+ * the active one, which then owns the shared HUBP 3DLUT fast load.
+ */
+ if (plane_state->cm.flags.bits.rmcm_enable && hws->funcs.set_rmcm_luts) {
+ if (hws->funcs.disable_mcm_luts)
+ hws->funcs.disable_mcm_luts(params->mpc, params->mpcc_id);
+
+ result = hws->funcs.set_rmcm_luts(params);
+ } else {
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(params->dc, params->rmcm,
+ params->hubp, params->mpcc_id);
+
+ if (hws->funcs.set_mcm_luts)
+ result = hws->funcs.set_mcm_luts(params->dc, dpp, params->hubp,
+ params->primary_hubp, params->mpc, params->mpcc_id,
+ params->stream, plane_state);
+ }
return result;
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
index 225128962216..7e68029f1e12 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
@@ -44,6 +44,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index 6e1079377f48..f9d8ff6ce010 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -872,9 +872,13 @@ void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
*/
void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
+ struct dce_hwseq *hws = dc->hwseq;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
+ /* Clearing 3DLUT fast load writes to HUBP, so it must precede hubp_clk_cntl() below */
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(dc, pipe_ctx->plane_res.rmcm, hubp, pipe_ctx->plane_res.mpcc_inst);
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
@@ -1642,10 +1646,9 @@ void dcn35_hardware_release(struct dc *dc)
dc->hwss.hw_block_power_up(dc, &pg_update_state);
}
-void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_abort_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- if (!dc_dmub_srv_is_cursor_offload_enabled(dc))
- return;
+ struct dc *dc = dpp->ctx->dc;
/*
* Insert a blank update to modify the write index and set pipe_mask to 0.
@@ -1664,56 +1667,46 @@ void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pip
*/
if (dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe);
+ dc->hwss.begin_cursor_offload_update(dmub, dpp, hubp, stream_idx);
if (dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe);
+ dc->hwss.commit_cursor_offload_update(dmub, dpp, hubp, stream_idx);
}
-void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_begin_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- uint32_t stream_idx, write_idx, payload_idx;
-
- if (!top_pipe)
- return;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
+ uint32_t write_idx, payload_idx;
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_start = write_idx;
cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask = 0;
- if (pipe->plane_res.hubp)
- pipe->plane_res.hubp->cursor_offload = true;
+ if (hubp)
+ hubp->cursor_offload = true;
- if (pipe->plane_res.dpp)
- pipe->plane_res.dpp->cursor_offload = true;
+ if (dpp)
+ dpp->cursor_offload = true;
}
-void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_commit_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_shared_state_cursor_offload_stream_v1 *shared_stream;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- uint32_t stream_idx, write_idx, payload_idx;
+ uint32_t write_idx, payload_idx;
- if (pipe->plane_res.hubp)
- pipe->plane_res.hubp->cursor_offload = false;
+ if (hubp)
+ hubp->cursor_offload = false;
- if (pipe->plane_res.dpp)
- pipe->plane_res.dpp->cursor_offload = false;
+ if (dpp)
+ dpp->cursor_offload = false;
- if (!top_pipe)
- return;
-
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- shared_stream = &dc->ctx->dmub_srv->dmub->shared_state[DMUB_SHARED_STATE_FEATURE__CURSOR_OFFLOAD_V1]
+ shared_stream = &dmub->shared_state[DMUB_SHARED_STATE_FEATURE__CURSOR_OFFLOAD_V1]
.data.cursor_offload_v1.offload_streams[stream_idx];
shared_stream->last_write_idx = write_idx;
@@ -1722,23 +1715,17 @@ void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pi
cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_finish = write_idx;
}
-void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn30_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
-
- if (!top_pipe || !hubp || !dpp)
- return;
+ uint32_t write_idx, payload_idx;
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn30;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn30;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -1767,7 +1754,7 @@ void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
@@ -1835,3 +1822,49 @@ void dcn35_disable_link_output(struct dc_link *link,
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
+
+bool dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
+{
+ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
+
+ if (!dc->ctx || !dc->ctx->dmub_srv)
+ return false;
+
+ /* if not support inbox0 lock, would not use inbox0 lock mechanism */
+ if (!dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support)
+ return false;
+
+ if (lock) {
+ if (!dc_dmub_srv_is_cursor_offload_enabled(dc) &&
+ !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
+ return false;
+ }
+
+ hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
+ hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
+ hw_lock_cmd.bits.lock = lock;
+ hw_lock_cmd.bits.should_release = !lock;
+ dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+
+ return true;
+}
+
+void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params)
+{
+ struct dc *dc = params->dmub_hw_control_lock_fast_params.dc;
+ bool lock = params->dmub_hw_control_lock_fast_params.lock;
+
+ /* if not support inbox0 lock, would not use inbox0 lock mechanism */
+ if (!dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support)
+ return;
+
+ if (params->dmub_hw_control_lock_fast_params.is_required) {
+ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
+
+ hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
+ hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
+ hw_lock_cmd.bits.lock = lock;
+ hw_lock_cmd.bits.should_release = !lock;
+ dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index 235ebf00bd1f..9f779e408ec6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -27,6 +27,8 @@
#ifndef __DC_HWSS_DCN35_H__
#define __DC_HWSS_DCN35_H__
+#include "inc/core_types.h"
+#include "dc.h"
#include "hw_sequencer_private.h"
struct dc;
@@ -103,15 +105,19 @@ bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
void dcn35_hardware_release(struct dc *dc);
-void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_abort_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx);
+void dcn35_begin_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx);
+void dcn35_commit_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+void dcn35_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
const struct dc_stream_state *stream);
void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe);
void dcn35_disable_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal);
+bool dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
+void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params);
#endif /* __DC_HWSS_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index c9125cc25d15..69fa91aeb836 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -48,6 +48,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
index e6f7d57cbfed..3ceaa4590148 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
@@ -47,6 +47,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 7b089ae5c9c3..8f202206c3c4 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -457,6 +457,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* 1D LUT */
lut_enable = cm->flags.bits.blend_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (lut_enable) {
if (cm->blend_func.type == TF_TYPE_HWPWL)
@@ -483,6 +486,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* Shaper */
lut_enable = cm->flags.bits.shaper_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
if (lut_enable) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (cm->shaper_func.type == TF_TYPE_HWPWL)
@@ -514,6 +520,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* 3DLUT */
lut_enable = cm->flags.bits.lut3d_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
/* Fast (DMA) Load Mode */
/* MPC */
@@ -1547,25 +1556,27 @@ void dcn401_optimize_bandwidth_sequence(struct dc *dc,
dc->clk_mgr, context, true, seq_state);
}
-void dcn401_dmub_hw_control_lock(struct dc *dc,
+bool dcn401_dmub_hw_control_lock(struct dc *dc,
struct dc_state *context,
bool lock)
{
(void)context;
- /* use always for now */
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
- return;
+ return false;
- if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
- return;
+ if (lock) {
+ if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
+ return false;
+ }
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ return true;
}
void dcn401_dmub_hw_control_lock_fast(union block_sequence_params *params)
@@ -3089,23 +3100,17 @@ void dcn401_plane_atomic_power_down(struct dc *dc,
hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
}
-void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn401_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn401_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
-
- if (!top_pipe || !hubp || !dpp)
- return;
+ uint32_t write_idx, payload_idx;
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn401;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn401;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -3142,7 +3147,7 @@ void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pip
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
p->HUBP0_DCHUBP_MALL_CONFIG__USE_MALL_FOR_CURSOR = hubp->use_mall_for_cursor;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
void dcn401_plane_atomic_power_down_sequence(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
index 756b2d98a930..43bea09fb205 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
@@ -78,7 +78,7 @@ void dcn401_optimize_bandwidth_sequence(struct dc *dc,
struct dc_state *context,
struct block_sequence_state *seq_state);
-void dcn401_dmub_hw_control_lock(struct dc *dc,
+bool dcn401_dmub_hw_control_lock(struct dc *dc,
struct dc_state *context,
bool lock);
void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable);
@@ -136,7 +136,8 @@ void dcn401_blank_pixel_data_sequence(
bool blank,
struct block_sequence_state *seq_state);
void dcn401_initialize_min_clocks(struct dc *dc);
-void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn401_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn401_program_all_writeback_pipes_in_tree_sequence(
struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
index 783415e4e3a1..5ac79c32ee48 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
@@ -23,6 +23,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn401_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index 23d4786ea246..21c3d108abe9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -402,112 +402,226 @@ void dcn42_program_cm_hist(
plane_state->cm_hist_control, plane_state->color_space);
}
-static bool dc_is_rmcm_3dlut_supported(struct hubp *hubp, struct mpc *mpc)
+/* RMCM is per-pipe and reloads through its own HUBP, unlike MCM which is shared by
+ * the plane's pipes and always reloads through the primary one.
+ */
+void dcn42_trigger_3dlut_dma_load(struct pipe_ctx *pipe_ctx)
{
- if (mpc->funcs->rmcm.power_on_shaper_3dlut &&
- mpc->funcs->rmcm.fl_3dlut_configure &&
- hubp->funcs->hubp_program_3dlut_fl_config)
- return true;
+ struct hubp *hubp;
+ bool use_rmcm = pipe_ctx->plane_state && pipe_ctx->plane_state->cm.flags.bits.rmcm_enable;
+
+ if (use_rmcm) {
+ hubp = pipe_ctx->plane_res.hubp;
+ } else {
+ const struct pipe_ctx *primary_dpp_pipe_ctx = resource_get_primary_dpp_pipe(pipe_ctx);
+
+ hubp = primary_dpp_pipe_ctx ? primary_dpp_pipe_ctx->plane_res.hubp : NULL;
+ }
- return false;
+ if (hubp && hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
}
-bool dcn42_program_rmcm_luts(
- struct dc *dc,
- struct dpp *dpp,
- struct hubp *hubp,
- const struct dc_plane_cm *cm,
- struct mpc *mpc,
- int mpcc_id,
- struct dc_stream_state *stream)
+/* Takes the MCM out of the pipe. The caller programs the HUBP fast load afterwards. */
+void dcn42_disable_mcm_luts(struct mpc *mpc, int mpcc_id)
+{
+ if (!mpc || !mpc->funcs->program_lut_mode)
+ return;
+
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+}
+
+static void dcn42_detach_rmcm(struct rmcm *rmcm)
{
- union mcm_lut_params m_lut_params = {0};
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm->inst, RMCM_FL_HUBP_IDX_NONE);
- struct mpc_fl_3dlut_config mpc_fl_config;
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm->inst, RMCM_MPCC_ID_NONE);
+}
+
+/* MPC makes an MPCC bypass RMCM once more than one instance is bound to it, so drop every
+ * instance that could still point at this MPCC. One the driver has not programmed yet counts,
+ * as its MPC_RMCM_CNTL may still hold a boot value.
+ */
+void dcn42_release_rmcm_from_mpcc(struct dc *dc, int mpcc_id, const struct rmcm *keep)
+{
+ int i;
- bool bypass_rmcm_shaper = false;
- // true->false when it can be allocated at DI time
- struct dc_rmcm_3dlut *rmcm_3dlut = dc_stream_get_3dlut_for_stream(dc, stream, false);
+ for (i = 0; i < dc->res_pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ struct rmcm *rmcm = dc->res_pool->rmcm[i];
- bool lut_enable = false;
- bool lut_bank_a = true;
+ if (!rmcm || !rmcm->funcs)
+ continue;
- //check to see current pipe is part of a stream with allocated rmcm 3dlut
- if (!rmcm_3dlut)
- return false;
+ if (rmcm == keep)
+ continue;
- /* Determine the LUT bank currently active in HW and switch to the other
- * bank to preserve double-buffering (mirrors dcn401_set_mcm_luts).
- */
- if (mpc->funcs->rmcm.get_3dlut_mode)
- mpc->funcs->rmcm.get_3dlut_mode(mpc, mpcc_id, &lut_enable, &lut_bank_a);
+ /* An instance the driver has not programmed yet counts as bound, because its
+ * MPC_RMCM_CNTL may still hold a boot value.
+ */
+ if (rmcm->mpcc_id == mpcc_id || rmcm->mpcc_id == RMCM_MPCC_ID_UNKNOWN)
+ dcn42_detach_rmcm(rmcm);
+ }
+}
+
+/* Leaves mpcc_id with no RMCM in its path. A NULL hubp keeps the shared 3DLUT fast load
+ * untouched, for when another block already owns that HUBP.
+ */
+void dcn42_disable_rmcm_luts(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id)
+{
+ if (rmcm && rmcm->funcs) {
+ /* HW blocks 3DLUT writes until FL mode is cleared from HUBP on VUpdate, so
+ * tear fast load down while the HUBP is still clocked.
+ */
+ if (hubp && hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
+ }
+
+ dcn42_detach_rmcm(rmcm);
+ }
+
+ dcn42_release_rmcm_from_mpcc(dc, mpcc_id, NULL);
+}
+
+bool dcn42_set_rmcm_luts(struct set_input_transfer_func_params *params)
+{
+ struct dpp *dpp_base = params->dpp;
+ struct hubp *hubp = params->hubp;
+ const struct dc_plane_cm *cm = &params->plane_state->cm;
+ struct rmcm *rmcm = params->rmcm;
+ int rmcm_inst;
+ union rmcm_lut_params m_lut_params = {0};
+ struct dc_3dlut_dma lut3d_dma;
+ bool lut_enable;
+ bool lut_bank_a;
+ bool rval;
+ bool result = true;
+
+ /* No RMCM on this plane, so there is nothing to program */
+ if (!rmcm || !rmcm->funcs) {
+ return true;
+ }
+
+ rmcm_inst = rmcm->inst;
+
+ /* decide LUT bank based on current in use */
+ if (rmcm->funcs->get_lut_mode) {
+ rmcm->funcs->get_lut_mode(rmcm, MCM_LUT_SHAPER, rmcm_inst, &lut_enable, &lut_bank_a);
+ if (!lut_enable) {
+ rmcm->funcs->get_lut_mode(rmcm, MCM_LUT_3DLUT, rmcm_inst, &lut_enable, &lut_bank_a);
+ }
+ } else {
+ lut_enable = false;
+ lut_bank_a = true;
+ }
- if (lut_enable)
+ /* switch to the next bank */
+ if (lut_enable) {
lut_bank_a = !lut_bank_a;
+ }
/* Shaper */
- if (cm->flags.bits.shaper_enable) {
+ lut_enable = cm->flags.bits.shaper_enable != 0;
+ if (lut_enable) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
-
- if (cm->shaper_func.type == TF_TYPE_HWPWL) {
+ if (cm->shaper_func.type == TF_TYPE_HWPWL)
m_lut_params.pwl = &cm->shaper_func.pwl;
- } else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
+ else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
ASSERT(false);
- cm_helper_translate_curve_to_hw_format(
- dc->ctx,
+ rval = cm_helper_translate_curve_to_hw_format(params->plane_state->ctx,
&cm->shaper_func,
- &dpp->shaper_params, true);
- m_lut_params.pwl = &dpp->shaper_params;
+ &dpp_base->shaper_params,
+ true);
+ m_lut_params.pwl = rval ? &dpp_base->shaper_params : NULL;
}
- if (m_lut_params.pwl) {
- if (mpc->funcs->rmcm.populate_lut)
- mpc->funcs->rmcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
- if (mpc->funcs->rmcm.program_lut_mode)
- mpc->funcs->rmcm.program_lut_mode(mpc, !bypass_rmcm_shaper, lut_bank_a, mpcc_id);
- } else {
- //RMCM 3dlut won't work without its shaper
- return false;
+ if (!m_lut_params.pwl) {
+ lut_enable = false;
}
+ } else {
+ lut_enable = false;
}
- /* 3DLUT */
- if (!cm->flags.bits.lut3d_dma_enable) {
- /* RMCM host (non-DMA) 3DLUT load is not implemented; fail fast
- * instead of silently reporting success
- */
- BREAK_TO_DEBUGGER();
- return false;
- } else {
- if (!dc_is_rmcm_3dlut_supported(hubp, mpc))
- return false;
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_SHAPER, lut_enable, lut_bank_a,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+ if (lut_enable && rmcm->funcs->populate_lut)
+ rmcm->funcs->populate_lut(rmcm, MCM_LUT_SHAPER, m_lut_params, lut_bank_a, rmcm_inst);
- //seems to be only for the MCM
- mpc_fl_config.enabled = cm->flags.bits.lut3d_enable != 0u;
- mpc_fl_config.size = cm->lut3d_dma.size;
- mpc_fl_config.select_lut_bank_a = lut_bank_a;
- mpc_fl_config.bit_depth = 0;
- mpc_fl_config.hubp_index = hubp->inst;
- mpc_fl_config.bias = cm->lut3d_dma.bias;
- mpc_fl_config.scale = cm->lut3d_dma.scale;
+ /* NOTE: Toggling from DMA->Host is not supported atomically as hardware
+ * blocks writes until 3DLUT FL mode is cleared from HUBP on VUpdate.
+ * Expectation is either option is used consistently.
+ */
- //1. power down the block
- mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, false);
+ /* 3DLUT */
+ lut_enable = cm->flags.bits.lut3d_enable != 0;
+ if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
+ /* Fast (DMA) Load Mode */
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, lut_bank_a,
+ cm->lut3d_dma.size,
+ cm->lut3d_dma.bias, cm->lut3d_dma.scale,
+ rmcm_inst);
- //2. program RMCM - 3dlut reg programming
- mpc->funcs->rmcm.fl_3dlut_configure(mpc, &mpc_fl_config, mpcc_id);
+ if (rmcm->funcs->program_lut_read_write_control)
+ rmcm->funcs->program_lut_read_write_control(rmcm, MCM_LUT_3DLUT, lut_bank_a, true, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, hubp->inst);
/* HUBP */
if (hubp->funcs->hubp_program_3dlut_fl_config)
hubp->funcs->hubp_program_3dlut_fl_config(hubp, &cm->lut3d_dma);
+ if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
+ hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, cm->lut3d_dma.format);
+
if (hubp->funcs->hubp_program_3dlut_fl_addr)
hubp->funcs->hubp_program_3dlut_fl_addr(hubp, &cm->lut3d_dma.addr);
- //3. power on the block
- mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, true);
+ if (hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
+ } else {
+ /* GPU memory only supports fast load path */
+ BREAK_TO_DEBUGGER();
+ lut_enable = false;
+ result = false;
+ }
+ } else {
+ /* RMCM has no host load path - its 3DLUT can only be fetched by HUBP fast
+ * load, so asking for one without DMA is a programming error.
+ */
+ ASSERT(!lut_enable);
+ result = !lut_enable;
+ lut_enable = false;
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, lut_bank_a,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, RMCM_FL_HUBP_IDX_NONE);
+
+ /* HUBP */
+ memset(&lut3d_dma, 0, sizeof(lut3d_dma));
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &lut3d_dma);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
}
- return true;
+ /* Connect to the MPCC only once the LUTs are loaded. Teardown is done by
+ * disable_rmcm_luts, at plane teardown or when the plane switches back to MCM.
+ */
+ dcn42_release_rmcm_from_mpcc(params->dc, params->mpcc_id, rmcm);
+
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm_inst, params->mpcc_id);
+
+ return result;
}
bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
@@ -516,25 +630,11 @@ bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
struct dc_plane_state *plane_state)
{
bool result;
- const struct dc_plane_cm *cm = &plane_state->cm;
/* MCM */
result = dcn401_set_mcm_luts(dc, dpp, hubp, primary_hubp, mpc, mpcc_id,
stream, plane_state);
- /* RMCM */
- if (cm->flags.bits.rmcm_enable && cm->flags.bits.lut3d_dma_enable) {
- /* TODO - move RMCM to its own block */
- dcn42_program_rmcm_luts(
- dc,
- dpp,
- hubp,
- cm,
- mpc,
- mpcc_id,
- stream);
- }
-
return result;
}
void dcn42_hardware_release(struct dc *dc)
@@ -683,7 +783,7 @@ void dcn42_prepare_bandwidth(
/* valid C-state watermarks have now been committed to HW, so it
* is safe to vote "allow" to PMFW.
*/
- if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+ if (dc->clk_mgr->funcs->notify_cstate_disable)
dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, false);
}
@@ -1088,25 +1188,28 @@ void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
return;
}
-void dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
+bool dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
{
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
- return;
+ return false;
/* Use helper to check PSR/Replay for all streams in context */
- if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)
- && !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
- return;
+ if (lock) {
+ if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)
+ && !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
+ return false;
+ }
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ return true;
}
void dcn42_dmub_hw_control_lock_fast(union block_sequence_params *params)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
index 61d1217a30df..31b92274a2f5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
@@ -20,14 +20,13 @@ bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
struct dc_stream_state *stream,
struct dc_plane_state *plane_state);
-bool dcn42_program_rmcm_luts(
- struct dc *dc,
- struct dpp *dpp,
- struct hubp *hubp,
- const struct dc_plane_cm *cm,
- struct mpc *mpc,
- int mpcc_id,
- struct dc_stream_state *stream);
+void dcn42_disable_rmcm_luts(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id);
+void dcn42_release_rmcm_from_mpcc(struct dc *dc, int mpcc_id, const struct rmcm *keep);
+void dcn42_disable_mcm_luts(struct mpc *mpc, int mpcc_id);
+void dcn42_trigger_3dlut_dma_load(struct pipe_ctx *pipe_ctx);
+
+bool dcn42_set_rmcm_luts(struct set_input_transfer_func_params *params);
+
void dcn42_hardware_release(struct dc *dc);
void dcn42_prepare_bandwidth(
@@ -44,7 +43,7 @@ void dcn42_hw_block_power_up(struct dc *dc,
struct pg_block_update *update_state);
void dcn42_root_clock_control(struct dc *dc,
struct pg_block_update *update_state, bool power_on);
-void dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
+bool dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
void dcn42_dmub_hw_control_lock_fast(union block_sequence_params *params);
void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc);
void dcn42_power_down_on_boot(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
index aad1885cc988..faeb365dbcab 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
@@ -26,10 +26,11 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn401_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
+ .trigger_3dlut_dma_load = dcn42_trigger_3dlut_dma_load,
.enable_accelerated_mode = dce110_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
@@ -151,6 +152,9 @@ static const struct hwseq_private_funcs dcn42_private_funcs = {
.set_hdr_multiplier = dcn10_set_hdr_multiplier,
.wait_for_blank_complete = dcn20_wait_for_blank_complete,
.set_mcm_luts = dcn42_set_mcm_luts,
+ .set_rmcm_luts = dcn42_set_rmcm_luts,
+ .disable_mcm_luts = dcn42_disable_mcm_luts,
+ .disable_rmcm_luts = dcn42_disable_rmcm_luts,
.program_mall_pipe_config = dcn32_program_mall_pipe_config,
.update_mall_sel = dcn32_update_mall_sel,
.calculate_dccg_k1_k2_values = NULL,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
index c13d1ad8d000..b1a916ac04e7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
@@ -67,7 +67,8 @@ static void dcn50_initialize_min_clocks(struct dc *dc)
* audio corruption. Read current DISPCLK from DENTIST and request the same
* freq to ensure that the timing is valid and unchanged.
*/
- clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
+ if (dc->clk_mgr->funcs->get_dispclk_from_dentist)
+ clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
}
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
clocks->fclk_p_state_change_support = true;
@@ -201,8 +202,14 @@ void dcn50_update_dchubp_dpp(
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
@@ -638,7 +645,8 @@ void dcn50_init_hw(struct dc *dc)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
- dcn50_initialize_min_clocks(dc);
+ if (dc->clk_mgr && dc->clk_mgr->funcs)
+ dcn50_initialize_min_clocks(dc);
/* On HW init, allow idle optimizations after pipes have been turned off.
*
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
index 0e6526e92544..ef1c10bc9bfa 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
@@ -31,6 +31,7 @@
#include "dce110/dce110_hwseq.h"
#include "dcn32/dcn32_hwseq.h"
#include "dcn401/dcn401_hwseq.h"
+#include "dcn42/dcn42_hwseq.h"
#include "dcn50/dcn50_hwseq.h"
#include "dcn60_hwseq.h"
#include "dcn401/dcn401_resource.h"
@@ -52,6 +53,127 @@
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
+bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params)
+{
+ struct dpp *dpp_base = params->dpp;
+ struct hubp *hubp = params->hubp;
+ const struct dc_plane_cm *cm = &params->plane_state->cm;
+ struct rmcm *rmcm = params->rmcm;
+ int rmcm_inst;
+ union rmcm_lut_params m_lut_params = {0};
+ struct dc_3dlut_dma lut3d_dma;
+ bool lut_enable;
+ /* DCN60 has a single LUT SRAM per RMCM - always bank A. */
+ bool rval;
+ bool result = true;
+
+ /* No RMCM on this plane, so there is nothing to program */
+ if (!rmcm || !rmcm->funcs) {
+ return true;
+ }
+
+ rmcm_inst = rmcm->inst;
+
+ /* Shaper */
+ lut_enable = cm->flags.bits.shaper_enable != 0;
+ if (lut_enable) {
+ memset(&m_lut_params, 0, sizeof(m_lut_params));
+ if (cm->shaper_func.type == TF_TYPE_HWPWL)
+ m_lut_params.pwl = &cm->shaper_func.pwl;
+ else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
+ ASSERT(false);
+ rval = cm_helper_translate_curve_to_hw_format(params->plane_state->ctx,
+ &cm->shaper_func,
+ &dpp_base->shaper_params,
+ true);
+ m_lut_params.pwl = rval ? &dpp_base->shaper_params : NULL;
+ }
+ if (!m_lut_params.pwl) {
+ lut_enable = false;
+ }
+ } else {
+ lut_enable = false;
+ }
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_SHAPER, lut_enable, true,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+ if (lut_enable && rmcm->funcs->populate_lut)
+ rmcm->funcs->populate_lut(rmcm, MCM_LUT_SHAPER, m_lut_params, true, rmcm_inst);
+
+ /* NOTE: Toggling from DMA->Host is not supported atomically as hardware
+ * blocks writes until 3DLUT FL mode is cleared from HUBP on VUpdate.
+ * Expectation is either option is used consistently.
+ */
+
+ /* 3DLUT */
+ lut_enable = cm->flags.bits.lut3d_enable != 0;
+ if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
+ /* Fast (DMA) Load Mode */
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, true,
+ cm->lut3d_dma.size,
+ cm->lut3d_dma.bias, cm->lut3d_dma.scale,
+ rmcm_inst);
+
+ if (rmcm->funcs->program_lut_read_write_control)
+ rmcm->funcs->program_lut_read_write_control(rmcm, MCM_LUT_3DLUT, true, true, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, hubp->inst);
+
+ /* HUBP */
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &cm->lut3d_dma);
+
+ if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
+ hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, cm->lut3d_dma.format);
+
+ if (hubp->funcs->hubp_program_3dlut_fl_addr)
+ hubp->funcs->hubp_program_3dlut_fl_addr(hubp, &cm->lut3d_dma.addr);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
+ } else {
+ /* GPU memory only supports fast load path */
+ BREAK_TO_DEBUGGER();
+ result = false;
+ }
+ } else {
+ /* RMCM 3DLUT is fetched only by HUBP fast load, so a host load request is a
+ * programming error.
+ */
+ ASSERT(!lut_enable);
+ result = !lut_enable;
+ lut_enable = false;
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, true,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, RMCM_FL_HUBP_IDX_NONE);
+
+ /* HUBP */
+ memset(&lut3d_dma, 0, sizeof(lut3d_dma));
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &lut3d_dma);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
+ }
+
+ /* Connect to the MPCC only once the LUTs are loaded. Teardown is done by
+ * disable_rmcm_luts, at plane teardown or when the plane switches back to MCM.
+ */
+ dcn42_release_rmcm_from_mpcc(params->dc, params->mpcc_id, rmcm);
+
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm_inst, params->mpcc_id);
+
+ return result;
+}
+
static void dcn60_build_audio_output(
struct dc_state *state,
const struct pipe_ctx *pipe_ctx,
@@ -647,7 +769,8 @@ void dcn60_init_hw(struct dc *dc)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
- dcn401_initialize_min_clocks(dc);
+ if (dc->clk_mgr && dc->clk_mgr->funcs)
+ dcn401_initialize_min_clocks(dc);
/* On HW init, allow idle optimizations after pipes have been turned off.
*
@@ -790,23 +913,17 @@ void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.dpp, attributes);
}
-void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn60_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn60_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
+ uint32_t write_idx, payload_idx;
- if (!top_pipe || !hubp || !dpp)
- return;
-
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn60;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn60;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -843,7 +960,7 @@ void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
p->HUBPREQ0_CURSOR_SETTINGS__FORCE_CURSOR_TO_DISP_PREF = hubp->att.settings.bits.force_cursor_to_disp_pref;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
/**
@@ -874,7 +991,7 @@ static struct timing_generator *dcn60_get_ref_tg_for_hubbub_probe(
* @dc: DC structure
* @context: Committed dc state to resolve streams from
* @probe: Probe state to build sequence for
- * @status: Perfmon status to update with probe results
+ * @status: Prior perfmon status, then the result sink for the sequence
* @block_sequence: Block sequence to append steps to
* @num_steps: Number of steps in the block sequence
*
@@ -893,17 +1010,32 @@ static void dcn60_build_hubbub_perfmon_sequence(
uint32_t refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
struct timing_generator *ref_tg = dcn60_get_ref_tg_for_hubbub_probe(context);
struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps };
+ bool was_measuring = status->measuring;
if (!hubbub || !hubbub->funcs || !hubbub->funcs->perfmon.reset)
return;
- status->type = probe->type;
-
if (probe->target_state == DC_PROBE_NOT_MEASURING) {
hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
return;
}
+ if (probe->target_state == DC_PROBE_MEASURING) {
+ if (probe->type != DC_PROBE_URGENT_ASSERTION_COUNT ||
+ !hubbub->funcs->perfmon.start_measuring_urgent_assertion_count ||
+ !hubbub->funcs->perfmon.get_urgent_assertion_count)
+ return;
+
+ if (!was_measuring) {
+ hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
+ hwss_add_hubbub_perfmon_start_urgent_assertion_count(&seq_state, hubbub);
+ }
+
+ hwss_add_hubbub_perfmon_get_urgent_assertion_count(&seq_state, hubbub,
+ refclk_mhz, &status->u.urgent_assertion_count);
+ return;
+ }
+
if (probe->target_state != DC_PROBE_MEASURED || !ref_tg)
return;
@@ -943,7 +1075,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
hwss_add_hubbub_perfmon_get_out_of_order_bw(&seq_state, hubbub,
refclk_mhz, &status->u.bandwidth_mbps, NULL);
- break;
+ return;
case DC_PROBE_AVG_MEM_BW:
/* In-order counter accumulates over a full frame, so no timing group
@@ -960,7 +1092,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_in_order_bw(&seq_state, hubbub,
refclk_mhz, 0, &status->u.bandwidth_mbps, NULL);
- break;
+ return;
case DC_PROBE_MEM_LATENCY:
if (!hubbub->funcs->perfmon.start_measuring_memory_latencies ||
@@ -975,7 +1107,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_memory_latencies(&seq_state, hubbub,
refclk_mhz, &status->u.latency);
- break;
+ return;
case DC_PROBE_URGENT_ASSERTION_COUNT:
if (!hubbub->funcs->perfmon.start_measuring_urgent_assertion_count ||
@@ -990,7 +1122,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_urgent_assertion_count(&seq_state, hubbub,
refclk_mhz, &status->u.urgent_assertion_count);
- break;
+ return;
case DC_PROBE_PREFETCH_DATA_SIZE:
if (!hubbub->funcs->perfmon.start_measuring_prefetch_data_size ||
@@ -1005,7 +1137,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_prefetch_data_size(&seq_state, hubbub,
&status->u.prefetch_data_size);
- break;
+ return;
case DC_PROBE_URGENT_RAMP_LATENCY:
/* Requires caller-supplied window params not available in probe model. */
@@ -1019,10 +1151,24 @@ static void dcn60_build_hubbub_perfmon_sequence(
/**
* dcn60_update_probe_status - Set the valid flag on a latched probe result.
* @status: result sink whose u was written by the GET BLS step during execute
+ * @probe: current probe state used to determine measurement type and validity
*/
-static void dcn60_update_probe_status(struct dc_probe_status *status)
+static void dcn60_update_probe_status(
+ struct dc_probe_status *status,
+ const struct dc_probe_state *probe)
{
- switch (status->type) {
+ struct dc_probe_status result = *status;
+
+ memset(status, 0, sizeof(*status));
+
+ if (probe->target_state == DC_PROBE_NOT_MEASURING)
+ return;
+
+ status->type = probe->type;
+ status->measuring = probe->target_state == DC_PROBE_MEASURING;
+ status->u = result.u;
+
+ switch (probe->type) {
case DC_PROBE_PEAK_MEM_BW:
case DC_PROBE_PEAK_MEM_BW_STRESSED:
case DC_PROBE_AVG_MEM_BW:
@@ -1043,6 +1189,7 @@ static void dcn60_update_probe_status(struct dc_probe_status *status)
/**
* is_probe_measurement_type_for_hubbub - Returns true if the probe type is
* served by the hubbub perfmon block on DCN60.
+ * @type: the probe measurement type to classify
*/
static bool is_probe_measurement_type_for_hubbub(enum dc_probe_type type)
{
@@ -1078,11 +1225,11 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context)
return;
context->block_sequence_steps = 0;
- memset(context->probe_status, 0, sizeof(context->probe_status));
for (i = 0; i < context->probe_count; i++) {
if (is_probe_measurement_type_for_hubbub(context->probes[i].type))
- dcn60_build_hubbub_perfmon_sequence(dc, context, &context->probes[i],
+ dcn60_build_hubbub_perfmon_sequence(dc, context,
+ &context->probes[i],
&context->probe_status[i],
context->block_sequence,
&context->block_sequence_steps);
@@ -1091,7 +1238,7 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context)
hwss_execute_sequence(dc, context->block_sequence, context->block_sequence_steps);
for (i = 0; i < context->probe_count; i++)
- dcn60_update_probe_status(&context->probe_status[i]);
+ dcn60_update_probe_status(&context->probe_status[i], &context->probes[i]);
}
static bool dcn60_has_active_memory_request(const struct dc *dc)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
index b57d22d310b0..b880988ff1fc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
@@ -24,9 +24,12 @@ enum dc_status dcn60_apply_single_controller_ctx_to_hw(
void dcn60_init_hw(struct dc *dc);
void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx);
-void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn60_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn60_program_perfmon(struct dc *dc, struct dc_state *context);
bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable);
+bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params);
+
#endif /* __DC_HWSS_DCN60_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
index 37e88d45409b..4aaecd6f8bb7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
@@ -25,10 +25,11 @@ static const struct hw_sequencer_funcs dcn60_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn50_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
+ .trigger_3dlut_dma_load = dcn42_trigger_3dlut_dma_load,
.enable_accelerated_mode = dce110_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
@@ -147,7 +148,7 @@ static const struct hwseq_private_funcs dcn60_private_funcs = {
.init_blank = dcn32_init_blank,
.disable_vga = NULL,
.bios_golden_init = dcn10_bios_golden_init,
- .plane_atomic_disable = dcn20_plane_atomic_disable,
+ .plane_atomic_disable = dcn35_plane_atomic_disable,
.plane_atomic_power_down = dcn401_plane_atomic_power_down,
.plane_atomic_power_down_sequence = dcn401_plane_atomic_power_down_sequence,
.enable_power_gating_plane = NULL,
@@ -162,6 +163,9 @@ static const struct hwseq_private_funcs dcn60_private_funcs = {
.set_hdr_multiplier_sequence = dcn401_set_hdr_multiplier_sequence,
.wait_for_blank_complete = dcn20_wait_for_blank_complete,
.set_mcm_luts = dcn42_set_mcm_luts,
+ .set_rmcm_luts = dcn60_set_rmcm_luts,
+ .disable_mcm_luts = dcn42_disable_mcm_luts,
+ .disable_rmcm_luts = dcn42_disable_rmcm_luts,
.program_mall_pipe_config = NULL,
.update_mall_sel = NULL,
.calculate_dccg_k1_k2_values = NULL,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index f75e34a09dca..fc5935b1e8b7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -46,6 +46,7 @@ struct resource_pool;
struct dc_phy_addr_space_config;
struct dc_virtual_addr_space_config;
struct dpp;
+struct rmcm;
struct dce_hwseq;
struct link_resource;
struct dc_dmub_cmd;
@@ -91,8 +92,10 @@ struct program_triplebuffer_params {
};
struct update_plane_addr_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct hubp *hubp;
+ struct dc_plane_address address;
+ bool flip_immediate;
+ bool dcc;
};
struct set_input_transfer_func_params {
@@ -101,6 +104,7 @@ struct set_input_transfer_func_params {
struct hubp *hubp;
struct hubp *primary_hubp;
struct mpc *mpc;
+ struct rmcm *rmcm;
int mpcc_id;
struct dc_stream_state *stream;
struct input_pixel_processor *ipp;
@@ -837,11 +841,6 @@ struct hubp_program_mcache_id_and_split_coordinate_params {
struct mcache_regs_struct *mcache_regs;
};
-struct abort_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
-};
-
struct cursor_lock_params {
struct dc *dc;
struct pipe_ctx *pipe_ctx;
@@ -906,18 +905,32 @@ struct phantom_hubp_post_enable_params {
};
struct begin_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
};
struct update_cursor_offload_pipe_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ const struct dpp *dpp;
+ const struct hubp *hubp;
+ uint32_t stream_idx;
+ uint8_t pipe_idx;
};
struct commit_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
+};
+
+struct abort_cursor_offload_update_params {
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
};
struct stream_enc_update_hdmi_info_packets_params {
@@ -1446,6 +1459,10 @@ struct hw_sequencer_funcs {
struct dc_state *context);
void (*update_plane_addr)(const struct dc *dc,
struct pipe_ctx *pipe_ctx);
+ void (*prepare_plane_addr_update)(const struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program,
+ bool *flip_immediate);
void (*update_dchub)(struct dce_hwseq *hws,
struct dchub_init_data *dh_data);
void (*wait_for_mpcc_disconnect)(struct dc *dc,
@@ -1535,10 +1552,17 @@ struct hw_sequencer_funcs {
void (*set_cursor_position)(struct pipe_ctx *pipe);
void (*set_cursor_attribute)(struct pipe_ctx *pipe);
void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe);
- void (*abort_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*begin_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*commit_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*update_cursor_offload_pipe)(struct dc *dc, const struct pipe_ctx *pipe);
+ void (*abort_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*begin_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*commit_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*update_cursor_offload_pipe)(struct dmub_srv *dmub,
+ uint32_t stream_idx,
+ uint8_t pipe_idx,
+ const struct dpp *dpp,
+ const struct hubp *hubp);
void (*notify_cursor_offload_drr_update)(struct dc *dc, struct dc_state *context,
const struct dc_stream_state *stream);
void (*program_cursor_offload_now)(struct dc *dc, const struct pipe_ctx *pipe);
@@ -1695,7 +1719,7 @@ struct hw_sequencer_funcs {
const struct dc_state *cur_ctx,
const struct dc_state *new_ctx);
void (*wait_for_dcc_meta_propagation)(uint32_t delay);
- void (*dmub_hw_control_lock)(struct dc *dc,
+ bool (*dmub_hw_control_lock)(struct dc *dc,
struct dc_state *context,
bool lock);
void (*fams2_update_config)(struct dc *dc,
@@ -2126,8 +2150,6 @@ void hwss_dpp_set_scaler(union block_sequence_params *params);
void hwss_hubp_mem_program_viewport(union block_sequence_params *params);
-void hwss_abort_cursor_offload_update(union block_sequence_params *params);
-
void hwss_send_cursor_info_to_dmu(union block_sequence_params *params);
void hwss_set_cursor_attribute(union block_sequence_params *params);
@@ -2152,11 +2174,13 @@ void hwss_phantom_hubp_post_enable(union block_sequence_params *params);
void hwss_cursor_lock(union block_sequence_params *params);
-void hwss_begin_cursor_offload_update(union block_sequence_params *params);
+void hwss_begin_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
+
+void hwss_commit_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
-void hwss_commit_cursor_offload_update(union block_sequence_params *params);
+void hwss_update_cursor_offload_pipe(struct dc *dc, union block_sequence_params *params);
-void hwss_update_cursor_offload_pipe(union block_sequence_params *params);
+void hwss_abort_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
void hwss_setup_periodic_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
index 9730f51cf3c0..b6932b9bc206 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
@@ -73,6 +73,7 @@ struct timing_generator;
struct tg_color;
struct output_pixel_processor;
struct mpcc_blnd_cfg;
+struct rmcm;
struct hwseq_private_funcs {
@@ -193,6 +194,9 @@ struct hwseq_private_funcs {
struct hubp *primary_hubp, struct mpc *mpc, int mpcc_id,
struct dc_stream_state *stream,
struct dc_plane_state *plane_state);
+ bool (*set_rmcm_luts)(struct set_input_transfer_func_params *params);
+ void (*disable_mcm_luts)(struct mpc *mpc, int mpcc_id);
+ void (*disable_rmcm_luts)(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id);
void (*PLAT_58856_wa)(struct dc_state *context,
struct pipe_ctx *pipe_ctx);
void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable);
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 d2cca2c97a41..6563eaaa0c0c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -308,7 +308,7 @@ struct resource_pool {
struct hpo_dp_link_encoder *hpo_dp_link_enc[MAX_HPO_DP2_LINK_ENCODERS];
struct dc_3dlut *mpc_lut[MAX_PIPES];
struct dc_transfer_func *mpc_shaper[MAX_PIPES];
- struct dc_rmcm_3dlut rmcm_3dlut[MAX_RMCM_INST];
+ struct rmcm *rmcm[MAX_RMCM_INST];
struct {
unsigned int xtalin_clock_inKhz;
@@ -401,6 +401,7 @@ struct plane_resource {
struct transform *xfm;
struct dpp *dpp;
uint8_t mpcc_inst;
+ struct rmcm *rmcm;
struct dcn_fe_bandwidth bw;
};
@@ -558,6 +559,7 @@ struct resource_context {
unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS];
int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS];
bool is_mpc_3dlut_acquired[MAX_PIPES];
+ bool rmcm_in_use[MAX_RMCM_INST];
/* used to build scalar data in dml2 and for edp backlight programming */
struct pipe_ctx temp_pipe;
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index e756719308ab..4b7c55eeb0c6 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -193,6 +193,7 @@ struct dcn_dccg_reg_state {
struct dccg {
struct dc_context *ctx;
const struct dccg_funcs *funcs;
+ int inst;
int pipe_dppclk_khz[MAX_PIPES];
int ref_dppclk;
bool dpp_clock_gated[MAX_PIPES];
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 b31b144d2e8f..930b5533256f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -378,7 +378,8 @@ struct dpp_funcs {
void (*dpp_set_pregam_state)(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling);
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear);
void (*dpp_program_upsp)(
struct dpp *dpp_base,
const struct dscl_prog_data *dscl_prog_data);
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 9dc9317c28a4..a648ed3b012a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -87,6 +87,7 @@ enum hubp_3dlut_fl_addressing_mode {
};
enum hubp_3dlut_fl_width {
+ hubp_3dlut_fl_width_9 = 9,
hubp_3dlut_fl_width_17 = 17,
hubp_3dlut_fl_width_33 = 33,
hubp_3dlut_fl_width_17_transformed = 4916, //mpc default
@@ -175,7 +176,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,
+ bool dcc);
void (*hubp_program_pte_vm)(
struct hubp *hubp,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
index d863f4bdccad..75ebfab87efc 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
@@ -193,42 +193,6 @@ struct mpc_grph_gamut_adjustment {
enum mpcc_gamut_remap_id mpcc_gamut_remap_block_id;
};
-struct mpc_rmcm_regs {
- uint32_t rmcm_3dlut_mem_pwr_state;
- uint32_t rmcm_3dlut_mem_pwr_force;
- uint32_t rmcm_3dlut_mem_pwr_dis;
- uint32_t rmcm_3dlut_mem_pwr_mode;
- uint32_t rmcm_3dlut_size;
- uint32_t rmcm_3dlut_mode;
- uint32_t rmcm_3dlut_mode_cur;
- uint32_t rmcm_3dlut_read_sel;
- uint32_t rmcm_3dlut_30bit_en;
- uint32_t rmcm_3dlut_wr_en_mask;
- uint32_t rmcm_3dlut_ram_sel;
- uint32_t rmcm_3dlut_out_norm_factor;
- uint32_t rmcm_3dlut_fl_sel;
- uint32_t rmcm_3dlut_out_offset_r;
- uint32_t rmcm_3dlut_out_scale_r;
- uint32_t rmcm_3dlut_fl_done;
- uint32_t rmcm_3dlut_fl_soft_underflow;
- uint32_t rmcm_3dlut_fl_hard_underflow;
- uint32_t rmcm_cntl;
- uint32_t rmcm_shaper_mem_pwr_state;
- uint32_t rmcm_shaper_mem_pwr_force;
- uint32_t rmcm_shaper_mem_pwr_dis;
- uint32_t rmcm_shaper_mem_pwr_mode;
- uint32_t rmcm_shaper_lut_mode;
- uint32_t rmcm_shaper_mode_cur;
- uint32_t rmcm_shaper_lut_write_en_mask;
- uint32_t rmcm_shaper_lut_write_sel;
- uint32_t rmcm_shaper_offset_b;
- uint32_t rmcm_shaper_scale_b;
- uint32_t rmcm_shaper_rama_exp_region_start_b;
- uint32_t rmcm_shaper_rama_exp_region_start_seg_b;
- uint32_t rmcm_shaper_rama_exp_region_end_b;
- uint32_t rmcm_shaper_rama_exp_region_end_base_b;
-};
-
struct mpcc_sm_cfg {
bool enable;
/* 0-single plane,2-row subsampling,4-column subsampling,6-checkboard subsampling */
@@ -317,6 +281,7 @@ struct mpc_tree {
struct mpc {
const struct mpc_funcs *funcs;
struct dc_context *ctx;
+ int inst;
struct mpcc mpcc_array[MAX_MPCC];
struct pwl_params blender_params;
@@ -340,7 +305,6 @@ struct mpcc_state {
uint32_t rgam_mode;
uint32_t rgam_lut;
struct mpc_grph_gamut_adjustment gamut_remap;
- struct mpc_rmcm_regs rmcm_regs;
};
struct dcn_mpc_reg_state {
@@ -1143,33 +1107,6 @@ struct mpc_funcs {
const int mpcc_id,
bool *enable,
bool *lut_bank_a);
-
- /**
- * @rmcm:
- *
- * MPC RMCM new HW sequential programming functions
- */
- struct {
- void (*fl_3dlut_configure)(struct mpc *mpc, struct mpc_fl_3dlut_config *cfg, int mpcc_id);
- void (*enable_3dlut_fl)(struct mpc *mpc, bool enable, int mpcc_id);
- void (*update_3dlut_fast_load_select)(struct mpc *mpc, int mpcc_id, int hubp_idx);
- void (*program_lut_read_write_control)(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id);
- void (*program_lut_mode)(struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id);
- void (*program_3dlut_size)(struct mpc *mpc, const enum dc_cm_lut_size size, int mpcc_id);
- void (*program_bias_scale)(struct mpc *mpc, uint16_t bias, uint16_t scale, int mpcc_id);
- void (*program_bit_depth)(struct mpc *mpc, uint16_t bit_depth, int mpcc_id);
- bool (*is_config_supported)(uint32_t width);
-
- void (*power_on_shaper_3dlut)(struct mpc *mpc, uint32_t mpcc_id, bool power_on);
- void (*populate_lut)(struct mpc *mpc, const union mcm_lut_params params,
- bool lut_bank_a, int mpcc_id);
- void (*get_3dlut_mode)(struct mpc *mpc, int mpcc_id,
- bool *enable, bool *lut_bank_a);
- } rmcm;
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
new file mode 100644
index 000000000000..636cd0970438
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_H__
+#define __DC_RMCM_H__
+
+#include "dc_types.h"
+
+#define MAX_RMCM 2
+
+/* Detach values for the RMCM binding registers: no MPCC connected (MPC_RMCM_CNTL)
+ * and no HUBP driving 3DLUT fast load (MPC_RMCM_3DLUT_FL_SEL).
+ */
+#define RMCM_MPCC_ID_NONE 0xF
+#define RMCM_FL_HUBP_IDX_NONE 0xF
+
+/* MPC_RMCM_CNTL has not been written by the driver yet, so it may still hold
+ * whatever the boot state left there.
+ */
+#define RMCM_MPCC_ID_UNKNOWN (-1)
+
+/* MCM_LUT_ID is defined in mpc.h */
+enum MCM_LUT_ID;
+
+union rmcm_lut_params {
+ const struct pwl_params *pwl;
+ const struct tetrahedral_params *lut3d;
+};
+
+struct rmcm_regs {
+ uint32_t rmcm_3dlut_mem_pwr_state;
+ uint32_t rmcm_3dlut_mem_pwr_force;
+ uint32_t rmcm_3dlut_mem_pwr_dis;
+ uint32_t rmcm_3dlut_mem_pwr_mode;
+ uint32_t rmcm_3dlut_size;
+ uint32_t rmcm_3dlut_mode;
+ uint32_t rmcm_3dlut_mode_cur;
+ uint32_t rmcm_3dlut_read_sel;
+ uint32_t rmcm_3dlut_30bit_en;
+ uint32_t rmcm_3dlut_wr_en_mask;
+ uint32_t rmcm_3dlut_ram_sel;
+ uint32_t rmcm_3dlut_out_norm_factor;
+ uint32_t rmcm_3dlut_fl_sel;
+ uint32_t rmcm_3dlut_out_offset_r;
+ uint32_t rmcm_3dlut_out_scale_r;
+ uint32_t rmcm_3dlut_fl_done;
+ uint32_t rmcm_3dlut_fl_soft_underflow;
+ uint32_t rmcm_3dlut_fl_hard_underflow;
+ uint32_t rmcm_cntl;
+ uint32_t rmcm_shaper_mem_pwr_state;
+ uint32_t rmcm_shaper_mem_pwr_force;
+ uint32_t rmcm_shaper_mem_pwr_dis;
+ uint32_t rmcm_shaper_mem_pwr_mode;
+ uint32_t rmcm_shaper_lut_mode;
+ uint32_t rmcm_shaper_mode_cur;
+ uint32_t rmcm_shaper_lut_write_en_mask;
+ uint32_t rmcm_shaper_lut_write_sel;
+ uint32_t rmcm_shaper_offset_b;
+ uint32_t rmcm_shaper_scale_b;
+ uint32_t rmcm_shaper_rama_exp_region_start_b;
+ uint32_t rmcm_shaper_rama_exp_region_start_seg_b;
+ uint32_t rmcm_shaper_rama_exp_region_end_b;
+ uint32_t rmcm_shaper_rama_exp_region_end_base_b;
+};
+
+/**
+ * struct rmcm_state - RMCM hardware state
+ *
+ * Captures the current hardware state of a Relocatable MCM instance.
+ * Used for debugging, state readback, and hardware validation.
+ */
+struct rmcm_state {
+ /**
+ * @regs: Register state snapshot
+ */
+ struct rmcm_regs regs;
+};
+
+/**
+ * struct rmcm - RMCM hardware instance
+ *
+ * Represents a single RMCM (Relocatable MCM) hardware instance.
+ * DCN 4.2+ has 2 RMCM instances that are shared across streams.
+ */
+struct rmcm {
+ struct dc_context *ctx;
+ int inst;
+ /* MPCC bound through MPC_RMCM_CNTL; MPC bypasses RMCM entirely when two
+ * instances are bound to the same MPCC.
+ */
+ int mpcc_id;
+ const struct rmcm_funcs *funcs;
+};
+
+/**
+ * struct rmcm_funcs - RMCM hardware abstraction function pointers
+ *
+ * Function pointers for RMCM (Relocatable MCM) hardware operations.
+ * These provide the interface for programming the shared cross-stream
+ * color manager instances.
+ */
+struct rmcm_funcs {
+ void (*get_lut_mode)(struct rmcm *rmcm, const enum MCM_LUT_ID id, int rmcm_id, bool *enable, bool *lut_bank_a);
+ void (*program_lut_mode)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool enable, bool lut_bank_a, const enum dc_cm_lut_size size,
+ uint16_t bias, uint16_t scale, int rmcm_id);
+ void (*populate_lut)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id);
+ void (*program_lut_read_write_control)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id);
+ void (*update_3dlut_fast_load_select)(struct rmcm *rmcm, int rmcm_id, int hubp_idx);
+ void (*get_3dlut_fast_load_status)(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow);
+ void (*read_rmcm_state)(struct rmcm *rmcm, int rmcm_id, struct rmcm_state *s);
+ void (*connect_mpcc)(struct rmcm *rmcm, int rmcm_id, int mpcc_id);
+};
+
+#endif // __DC_RMCM_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 2eaba65894ab..52d4d57358cd 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
@@ -512,6 +512,7 @@ struct timing_generator_funcs {
uint32_t vtotal_change_limit);
void (*init_odm)(struct timing_generator *tg);
+ bool (*is_odm_enabled)(struct timing_generator *tg);
void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
void (*set_long_vtotal)(struct timing_generator *optc, const struct long_vtotal_params *params);
void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
index eaf20ca14bcc..b2f86c51d470 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
@@ -297,6 +297,8 @@ struct link_service {
bool (*edp_replay_residency)(const struct dc_link *link,
unsigned int *residency, const bool is_start,
const enum pr_residency_mode mode);
+ bool (*edp_replay_get_cumulative_residency)(const struct dc_link *link,
+ uint32_t *residency_milli_pct);
bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 8e21aaac06b3..21a6f90956e8 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -123,7 +123,8 @@ void resource_build_test_pattern_params(
struct resource_context *res_ctx,
struct pipe_ctx *pipe_ctx);
-enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format);
+enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format,
+ enum dc_scaling_linearity scaling_linearity);
bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx);
@@ -336,6 +337,21 @@ void resource_remove_dpp_pipes_for_plane_composition(
const struct dc_plane_state *plane_state);
/*
+ * RMCM resource management. Instances are handed out for a whole context at once so that a
+ * plane that is only now asking cannot evict one that is already using an instance.
+ * Tracking is via res_ctx->rmcm_in_use[].
+ */
+void resource_assign_rmcm(
+ struct dc_state *new_ctx,
+ const struct dc_state *cur_ctx,
+ const struct resource_pool *pool);
+
+void resource_release_rmcm(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct rmcm **rmcm);
+
+/*
* Update ODM slice count by acquiring or releasing pipes. If new slices need
* to be added, it is going to add them to the last ODM index. If existing
* slices need to be removed, it is going to remove them from the last ODM
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
index fa281de1d566..3b192c539f8b 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -223,6 +223,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
link_srv->edp_replay_residency = edp_replay_residency;
+ link_srv->edp_replay_get_cumulative_residency = edp_replay_get_cumulative_residency;
link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal;
link_srv->edp_wait_for_t12 = edp_wait_for_t12;
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
index 9883216dcc9d..e904c7dd320e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
@@ -1154,6 +1154,28 @@ bool edp_replay_residency(const struct dc_link *link,
return true;
}
+bool edp_replay_get_cumulative_residency(const struct dc_link *link,
+ uint32_t *residency_milli_pct)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmub_replay *replay = dc->res_pool->replay;
+ unsigned int panel_inst;
+
+ if (!dp_pr_get_pr_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ if (replay && link->replay_settings.replay_feature_enabled &&
+ replay->funcs->replay_get_cumulative_residency)
+ return replay->funcs->replay_get_cumulative_residency(replay,
+ (uint8_t)panel_inst, residency_milli_pct);
+
+ if (residency_milli_pct)
+ *residency_milli_pct = 0;
+
+ return true;
+}
+
+
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number)
{
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
index 51de13e2387e..0082f5e91878 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
@@ -60,6 +60,8 @@ bool edp_send_replay_cmd(struct dc_link *link,
bool edp_set_coasting_vtotal(struct dc_link *link, uint32_t coasting_vtotal, uint16_t frame_skip_number);
bool edp_replay_residency(const struct dc_link *link,
unsigned int *residency, const bool is_start, const enum pr_residency_mode mode);
+bool edp_replay_get_cumulative_residency(const struct dc_link *link,
+ uint32_t *residency_milli_pct);
bool edp_get_replay_state(const struct dc_link *link, uint64_t *state);
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number);
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
index 0f2294bedcc3..f9bd1d6e1642 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
@@ -503,6 +503,7 @@ void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
int i;
mpc10->base.ctx = ctx;
+ mpc10->base.inst = 0;
mpc10->base.funcs = &dcn10_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
index 0e09d073ab29..905d4f23f92a 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
@@ -588,6 +588,7 @@ void dcn20_mpc_construct(struct dcn20_mpc *mpc20,
int i;
mpc20->base.ctx = ctx;
+ mpc20->base.inst = 0;
mpc20->base.funcs = &dcn20_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
index 9cc6fd38da19..f3213ecb1745 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
@@ -1589,6 +1589,7 @@ void dcn30_mpc_construct(struct dcn30_mpc *mpc30,
int i;
mpc30->base.ctx = ctx;
+ mpc30->base.inst = 0;
mpc30->base.funcs = &dcn30_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
index 1f15ada109b6..61a1e3f06575 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
@@ -1036,6 +1036,7 @@ void dcn32_mpc_construct(struct dcn30_mpc *mpc30,
int i;
mpc30->base.ctx = ctx;
+ mpc30->base.inst = 0;
mpc30->base.funcs = &dcn32_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
index df92d8008fe6..e59454090691 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
@@ -680,6 +680,7 @@ void dcn401_mpc_construct(struct dcn401_mpc *mpc401,
int i;
mpc401->base.ctx = ctx;
+ mpc401->base.inst = 0;
mpc401->base.funcs = &dcn401_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
index 5a888e1e1cc5..37d024cfb3fb 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
@@ -63,680 +63,14 @@ void mpc42_update_blending(
mpcc->blnd_cfg = *blnd_cfg;
}
-/* RMCM Shaper functions */
-void mpc42_power_on_rmcm_shaper_3dlut(
- struct mpc *mpc,
- uint32_t mpcc_id,
- bool power_on)
-{
- uint32_t power_status_shaper = 2;
- uint32_t power_status_3dlut = 2;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- int max_retries = 10;
-
- REG_SET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], 0,
- MPC_RMCM_3DLUT_MEM_PWR_DIS, power_on == true ? 0 : 1);
- REG_SET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], 0,
- MPC_RMCM_SHAPER_MEM_PWR_DIS, power_on == true ? 0 : 1);
- /* wait for memory to fully power up */
- if (power_on && mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
- REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
- REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
- }
-
- /*read status is not mandatory, it is just for debugging*/
- REG_GET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, &power_status_shaper);
- REG_GET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, &power_status_3dlut);
-
- if (power_status_shaper != 0 && power_on == true)
- BREAK_TO_DEBUGGER();
-
- if (power_status_3dlut != 0 && power_on == true)
- BREAK_TO_DEBUGGER();
-}
-
-void mpc42_configure_rmcm_shaper_lut(
- struct mpc *mpc,
- bool is_ram_a,
- uint32_t mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_B, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_G, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_R[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_R, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0:1);
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_INDEX, 0);
-}
-
-void mpc42_program_rmcm_shaper_luta_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id)
-{
- const struct gamma_curve *curve;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
-
- curve = params->arr_curve_points;
- if (curve) {
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_0_1[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_2_3[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_4_5[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_6_7[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_8_9[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_10_11[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_12_13[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_14_15[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_16_17[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_18_19[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_20_21[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_22_23[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_24_25[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_26_27[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_28_29[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_30_31[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_32_33[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
- }
-}
-
-
-void mpc42_program_rmcm_shaper_lutb_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id)
-{
- const struct gamma_curve *curve;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
-
- curve = params->arr_curve_points;
- if (curve) {
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_0_1[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_2_3[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_4_5[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_6_7[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_8_9[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_10_11[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_12_13[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_14_15[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_16_17[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_18_19[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_20_21[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_22_23[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_24_25[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_26_27[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_28_29[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_30_31[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_32_33[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
- }
-}
-
-void mpc42_program_rmcm_shaper_lut(
- struct mpc *mpc,
- const struct pwl_result_data *rgb,
- uint32_t num,
- uint32_t mpcc_id)
-{
- uint32_t i, red, green, blue;
- uint32_t red_delta, green_delta, blue_delta;
- uint32_t red_value, green_value, blue_value;
-
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- for (i = 0; i < num; i++) {
-
- red = rgb[i].red_reg;
- green = rgb[i].green_reg;
- blue = rgb[i].blue_reg;
-
- red_delta = rgb[i].delta_red_reg;
- green_delta = rgb[i].delta_green_reg;
- blue_delta = rgb[i].delta_blue_reg;
-
- red_value = ((red_delta & 0x3ff) << 14) | (red & 0x3fff);
- green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff);
- blue_value = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, red_value);
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, green_value);
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, blue_value);
- }
-}
-
-void mpc42_enable_3dlut_fl(struct mpc *mpc, bool enable, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- //if enabled cho0se mpc 0, else: off (default value)
- REG_UPDATE(MPC_RMCM_CNTL[mpcc_id], MPC_RMCM_CNTL, enable ? 0 : 0xF); //0xF is not connected
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id], MPC_RMCM_3DLUT_WRITE_EN_MASK, 0);
-
- REG_UPDATE(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_DIS, enable ? 0 : 3);
-}
-
-void mpc42_update_3dlut_fast_load_select(struct mpc *mpc, int mpcc_id, int hubp_idx)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPC_RMCM_3DLUT_FL_SEL,
- hubp_idx);
-}
-
-void mpc42_populate_rmcm_lut(struct mpc *mpc, const union mcm_lut_params params,
- bool lut_bank_a, int mpcc_id)
-{
- const enum dc_lut_mode next_mode = lut_bank_a ? LUT_RAM_A : LUT_RAM_B;
- const struct pwl_params *lut_shaper = params.pwl;
-
- if (lut_shaper == NULL)
- return;
- if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
- mpc42_power_on_rmcm_shaper_3dlut(mpc, mpcc_id, true);
-
- mpc42_configure_rmcm_shaper_lut(mpc, next_mode == LUT_RAM_A, mpcc_id);
-
- if (next_mode == LUT_RAM_A)
- mpc42_program_rmcm_shaper_luta_settings(mpc, lut_shaper, mpcc_id);
- else
- mpc42_program_rmcm_shaper_lutb_settings(mpc, lut_shaper, mpcc_id);
-
- mpc42_program_rmcm_shaper_lut(
- mpc, lut_shaper->rgb_resulted, lut_shaper->hw_points_num, mpcc_id);
-
- mpc42_power_on_rmcm_shaper_3dlut(mpc, mpcc_id, false);
-}
-
-void mpc42_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- switch (id) {
- case MCM_LUT_3DLUT:
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
- (!enabled) ? 0 :
- (lut_bank_a) ? 1 : 2);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_RAM_SEL,
- (lut_bank_a) ? 0 : 1);
- break;
- case MCM_LUT_SHAPER:
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
-
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL,
- lut_bank_a == true ? 0:1);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
- MPC_RMCM_SHAPER_LUT_INDEX, 0);
- break;
- default:
- break;
- }
-}
-
-void mpc42_program_lut_mode(struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- if (enable) {
- REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[mpcc_id], MPC_RMCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2);
- } else {
- REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[mpcc_id], MPC_RMCM_SHAPER_LUT_MODE, 0);
- }
-}
-
-static uint32_t mpc42_get_rmcm_3dlut_width(
- const enum dc_cm_lut_size size)
-{
- uint32_t width = 0;
-
- switch (size) {
- case CM_LUT_SIZE_333333:
- width = 2;
- break;
- case CM_LUT_SIZE_171717:
- default:
- width = 0;
- break;
- }
-
- return width;
-}
-
-void mpc42_program_rmcm_3dlut_size(struct mpc *mpc,
- const enum dc_cm_lut_size size,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- uint32_t width = mpc42_get_rmcm_3dlut_width(size);
-
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id],
- MPC_RMCM_3DLUT_SIZE, width);
-}
-void mpc42_program_rmcm_3dlut_fast_load_bias_scale(struct mpc *mpc, uint16_t bias, uint16_t scale, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_R, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_R, scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_G[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_G, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_G, scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_B[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_B, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_B, scale);
-}
-
-void mpc42_program_rmcm_bit_depth(struct mpc *mpc, uint16_t bit_depth, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id], MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
-
- //program bit_depth
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_30BIT_EN,
- (bit_depth == 10) ? 1 : 0);
-}
-
-void mpc42_set_fl_config(
- struct mpc *mpc,
- struct mpc_fl_3dlut_config *cfg,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- uint32_t width = mpc42_get_rmcm_3dlut_width(cfg->size);
- /*
- From: Jie Zhou
-
- To program any of the memories content. The following sequence is used.
- Set the MPCC_OGAM/SHAPER/3DLUT/1DLUT_PWR_DIS to 1 (Only need to set the one
- that is being programmed) Set DISPCLK_G_PIPE<i>_GATE_DISABLE to 1 for the
- MPCC pipe that’s being used, so the memory’s clock is ungated. Program the
- target memory. Set the MPCC_OGAM/SHAPER/3DLUT/1DLUT_PWR_DIS back to 0.
- Set DISPCLK_G_PIPE<i>_GATE_DISABLE back to 0
- */
-
- //disconnect fl from mpc
- REG_SET(MPCC_MCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPCC_MCM_3DLUT_FL_SEL, 0xF);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
-
- //program bit_depth
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_30BIT_EN, (cfg->bit_depth == 10) ? 1 : 0);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_RAM_SEL, (cfg->select_lut_bank_a) ? 0 : 1);
-
- //bias and scale
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_R, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_R, cfg->scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_G[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_G, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_G, cfg->scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_B[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_B, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_B, cfg->scale);
-
- //width
- REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[mpcc_id],
- MPC_RMCM_3DLUT_SIZE, width,
- MPC_RMCM_3DLUT_MODE, (!cfg->enabled) ? 0 : (cfg->select_lut_bank_a) ? 1 : 2);
-
- //connect to hubp
- REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPC_RMCM_3DLUT_FL_SEL, cfg->hubp_index);
-
- //ENABLE
- //if enabled pick mpc 0, else: off (0xF)
- //in future we'll select specific MPC
- REG_UPDATE(MPC_RMCM_CNTL[mpcc_id], MPC_RMCM_CNTL, cfg->enabled ? 0 : 0xF);
-}
-
-void mpc42_get_rmcm_3dlut_mode(
- struct mpc *mpc,
- int mpcc_id,
- bool *enable,
- bool *lut_bank_a)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- uint32_t mode_current = 0;
-
- REG_GET(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE_CURRENT, &mode_current);
-
- /* MPC_RMCM_3DLUT_MODE encoding:
- * 0 -> disabled, 1 -> bank A, 2 -> bank B
- */
- *enable = mode_current != 0;
- *lut_bank_a = mode_current != 2;
-}
void mpc42_read_mpcc_state(
struct mpc *mpc,
int mpcc_inst,
struct mpcc_state *s)
{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
mpc1_read_mpcc_state(mpc, mpcc_inst, s);
-
- if (mpcc_inst < 2) {
- /* RMCM 3DLUT Status */
- REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[mpcc_inst], MPC_RMCM_3DLUT_MEM_PWR_FORCE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_force,
- MPC_RMCM_3DLUT_MEM_PWR_DIS, &s->rmcm_regs.rmcm_3dlut_mem_pwr_dis,
- MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_mode,
- MPC_RMCM_3DLUT_MEM_PWR_STATE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_state);
-
- REG_GET_3(MPC_RMCM_3DLUT_MODE[mpcc_inst], MPC_RMCM_3DLUT_SIZE, &s->rmcm_regs.rmcm_3dlut_size,
- MPC_RMCM_3DLUT_MODE, &s->rmcm_regs.rmcm_3dlut_mode,
- MPC_RMCM_3DLUT_MODE_CURRENT, &s->rmcm_regs.rmcm_3dlut_mode_cur);
-
- REG_GET_4(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_inst], MPC_RMCM_3DLUT_READ_SEL, &s->rmcm_regs.rmcm_3dlut_read_sel,
- MPC_RMCM_3DLUT_30BIT_EN, &s->rmcm_regs.rmcm_3dlut_30bit_en,
- MPC_RMCM_3DLUT_WRITE_EN_MASK, &s->rmcm_regs.rmcm_3dlut_wr_en_mask,
- MPC_RMCM_3DLUT_RAM_SEL, &s->rmcm_regs.rmcm_3dlut_ram_sel);
-
- REG_GET(MPC_RMCM_3DLUT_OUT_NORM_FACTOR[mpcc_inst], MPC_RMCM_3DLUT_OUT_NORM_FACTOR, &s->rmcm_regs.rmcm_3dlut_out_norm_factor);
-
- REG_GET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_inst], MPC_RMCM_3DLUT_FL_SEL, &s->rmcm_regs.rmcm_3dlut_fl_sel);
-
- REG_GET_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_inst], MPC_RMCM_3DLUT_OUT_OFFSET_R, &s->rmcm_regs.rmcm_3dlut_out_offset_r,
- MPC_RMCM_3DLUT_OUT_SCALE_R, &s->rmcm_regs.rmcm_3dlut_out_scale_r);
-
- REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[mpcc_inst], MPC_RMCM_3DLUT_FL_DONE, &s->rmcm_regs.rmcm_3dlut_fl_done,
- MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &s->rmcm_regs.rmcm_3dlut_fl_soft_underflow,
- MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &s->rmcm_regs.rmcm_3dlut_fl_hard_underflow);
-
- /* RMCM Shaper Status */
- REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[mpcc_inst], MPC_RMCM_SHAPER_MEM_PWR_FORCE, &s->rmcm_regs.rmcm_shaper_mem_pwr_force,
- MPC_RMCM_SHAPER_MEM_PWR_DIS, &s->rmcm_regs.rmcm_shaper_mem_pwr_dis,
- MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, &s->rmcm_regs.rmcm_shaper_mem_pwr_mode,
- MPC_RMCM_SHAPER_MEM_PWR_STATE, &s->rmcm_regs.rmcm_shaper_mem_pwr_state);
-
- REG_GET_2(MPC_RMCM_SHAPER_CONTROL[mpcc_inst], MPC_RMCM_SHAPER_LUT_MODE, &s->rmcm_regs.rmcm_shaper_lut_mode,
- MPC_RMCM_SHAPER_MODE_CURRENT, &s->rmcm_regs.rmcm_shaper_mode_cur);
-
- REG_GET_2(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_inst], MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, &s->rmcm_regs.rmcm_shaper_lut_write_en_mask,
- MPC_RMCM_SHAPER_LUT_WRITE_SEL, &s->rmcm_regs.rmcm_shaper_lut_write_sel);
-
- REG_GET(MPC_RMCM_SHAPER_OFFSET_B[mpcc_inst], MPC_RMCM_SHAPER_OFFSET_B, &s->rmcm_regs.rmcm_shaper_offset_b);
-
- REG_GET(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_inst], MPC_RMCM_SHAPER_SCALE_B, &s->rmcm_regs.rmcm_shaper_scale_b);
-
- REG_GET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[mpcc_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_start_b,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_start_seg_b);
-
- REG_GET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[mpcc_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_end_b,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_end_base_b);
-
- REG_GET(MPC_RMCM_CNTL[mpcc_inst], MPC_RMCM_CNTL, &s->rmcm_regs.rmcm_cntl);
- }
}
static const struct mpc_funcs dcn42_mpc_funcs = {
@@ -774,19 +108,6 @@ static const struct mpc_funcs dcn42_mpc_funcs = {
.program_lut_read_write_control = mpc401_program_lut_read_write_control,
.program_lut_mode = mpc401_program_lut_mode,
.get_lut_mode = mpc401_get_lut_mode,
- .rmcm = {
- .enable_3dlut_fl = mpc42_enable_3dlut_fl,
- .update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
- .program_lut_read_write_control = mpc42_program_rmcm_lut_read_write_control,
- .program_lut_mode = mpc42_program_lut_mode,
- .program_3dlut_size = mpc42_program_rmcm_3dlut_size,
- .program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
- .program_bit_depth = mpc42_program_rmcm_bit_depth,
- .power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
- .populate_lut = mpc42_populate_rmcm_lut,
- .fl_3dlut_configure = mpc42_set_fl_config,
- .get_3dlut_mode = mpc42_get_rmcm_3dlut_mode,
- },
};
void dcn42_mpc_construct(struct dcn42_mpc *mpc42,
@@ -800,6 +121,7 @@ void dcn42_mpc_construct(struct dcn42_mpc *mpc42,
int i;
mpc42->base.ctx = ctx;
+ mpc42->base.inst = 0;
mpc42->base.funcs = &dcn42_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
index af3b90af5396..213380832087 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
@@ -196,327 +196,7 @@
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_OFFSET_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_RAM_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh)
-
-#define MPC_RMCM_REG_LIST_DCN42(inst)\
- SRII(MPC_RMCM_SHAPER_CONTROL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_MODE, MPC_RMCM, inst), /*TODO: may need to add other 3DLUT regs*/\
- SRII(MPC_RMCM_3DLUT_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_DATA, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM, inst),\
- SRII(MPC_RMCM_CNTL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM, inst)
-
+ SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh)
#define MPC_REG_LIST_DCN42(inst) \
MPC_REG_LIST_DCN4_01_RI(inst),\
@@ -529,328 +209,11 @@
type MPCC_MCM_3DLUT_OUT_OFFSET_G;\
type MPCC_MCM_3DLUT_OUT_SCALE_G;\
type MPCC_MCM_3DLUT_OUT_OFFSET_B;\
- type MPCC_MCM_3DLUT_OUT_SCALE_B;\
- type MPC_RMCM_SHAPER_LUT_MODE;\
- type MPC_RMCM_SHAPER_MODE_CURRENT;\
- type MPC_RMCM_SHAPER_OFFSET_R;\
- type MPC_RMCM_SHAPER_OFFSET_G;\
- type MPC_RMCM_SHAPER_OFFSET_B;\
- type MPC_RMCM_SHAPER_SCALE_R;\
- type MPC_RMCM_SHAPER_SCALE_G;\
- type MPC_RMCM_SHAPER_SCALE_B;\
- type MPC_RMCM_SHAPER_LUT_INDEX;\
- type MPC_RMCM_SHAPER_LUT_DATA;\
- type MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK;\
- type MPC_RMCM_SHAPER_LUT_WRITE_SEL; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS;\
- type MPC_RMCM_3DLUT_MODE;\
- type MPC_RMCM_3DLUT_SIZE;\
- type MPC_RMCM_3DLUT_MODE_CURRENT;\
- type MPC_RMCM_3DLUT_INDEX; \
- type MPC_RMCM_3DLUT_DATA0; \
- type MPC_RMCM_3DLUT_DATA1; \
- type MPC_RMCM_3DLUT_DATA_30BIT; \
- type MPC_RMCM_3DLUT_WRITE_EN_MASK;\
- type MPC_RMCM_3DLUT_RAM_SEL;\
- type MPC_RMCM_3DLUT_30BIT_EN;\
- type MPC_RMCM_3DLUT_READ_SEL;\
- type MPC_RMCM_3DLUT_OUT_NORM_FACTOR;\
- type MPC_RMCM_3DLUT_OUT_OFFSET_R;\
- type MPC_RMCM_3DLUT_OUT_SCALE_R; \
- type MPC_RMCM_3DLUT_OUT_OFFSET_G; \
- type MPC_RMCM_3DLUT_OUT_SCALE_G; \
- type MPC_RMCM_3DLUT_OUT_OFFSET_B; \
- type MPC_RMCM_3DLUT_OUT_SCALE_B;\
- type MPC_RMCM_GAMUT_REMAP_COEF_FORMAT;\
- type MPC_RMCM_GAMUT_REMAP_MODE;\
- type MPC_RMCM_GAMUT_REMAP_MODE_CURRENT;\
- type MPC_RMCM_GAMUT_REMAP_C11_A;\
- type MPC_RMCM_GAMUT_REMAP_C12_A;\
- type MPC_RMCM_GAMUT_REMAP_C13_A; \
- type MPC_RMCM_GAMUT_REMAP_C14_A; \
- type MPC_RMCM_GAMUT_REMAP_C21_A; \
- type MPC_RMCM_GAMUT_REMAP_C22_A; \
- type MPC_RMCM_GAMUT_REMAP_C23_A;\
- type MPC_RMCM_GAMUT_REMAP_C24_A;\
- type MPC_RMCM_GAMUT_REMAP_C31_A;\
- type MPC_RMCM_GAMUT_REMAP_C32_A;\
- type MPC_RMCM_GAMUT_REMAP_C33_A;\
- type MPC_RMCM_GAMUT_REMAP_C34_A;\
- type MPC_RMCM_GAMUT_REMAP_C11_B;\
- type MPC_RMCM_GAMUT_REMAP_C12_B;\
- type MPC_RMCM_GAMUT_REMAP_C13_B; \
- type MPC_RMCM_GAMUT_REMAP_C14_B; \
- type MPC_RMCM_GAMUT_REMAP_C21_B; \
- type MPC_RMCM_GAMUT_REMAP_C22_B; \
- type MPC_RMCM_GAMUT_REMAP_C23_B;\
- type MPC_RMCM_GAMUT_REMAP_C24_B;\
- type MPC_RMCM_GAMUT_REMAP_C31_B;\
- type MPC_RMCM_GAMUT_REMAP_C32_B;\
- type MPC_RMCM_GAMUT_REMAP_C33_B;\
- type MPC_RMCM_GAMUT_REMAP_C34_B;\
- type MPC_RMCM_SHAPER_MEM_PWR_FORCE; \
- type MPC_RMCM_SHAPER_MEM_PWR_DIS; \
- type MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE; \
- type MPC_RMCM_3DLUT_MEM_PWR_FORCE;\
- type MPC_RMCM_3DLUT_MEM_PWR_DIS;\
- type MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE;\
- type MPC_RMCM_SHAPER_MEM_PWR_STATE;\
- type MPC_RMCM_3DLUT_MEM_PWR_STATE;\
- type MPC_RMCM_3DLUT_FL_SEL;\
- type MPC_RMCM_3DLUT_FL_DONE; \
- type MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW; \
- type MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW; \
- type MPC_RMCM_CNTL; \
- type MPC_RMCM_TEST_DEBUG_INDEX;\
- type MPC_RMCM_TEST_DEBUG_WRITE_EN;\
- type MPC_RMCM_TEST_DEBUG_DATA
+ type MPCC_MCM_3DLUT_OUT_SCALE_B
#define MPC_REG_VARIABLE_LIST_DCN42 \
MPC_REG_VARIABLE_LIST_DCN4_01 \
- uint32_t MPCC_CONTROL2[MAX_MPCC];\
- uint32_t MPC_RMCM_SHAPER_CONTROL[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_SCALE_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_SCALE_G_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_DATA[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_0_1[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_2_3[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_4_5[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_6_7[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_8_9[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_10_11[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_12_13[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_14_15[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_16_17[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_18_19[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_20_21[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_22_23[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_24_25[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_26_27[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_28_29[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_30_31[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_32_33[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_0_1[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_2_3[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_4_5[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_6_7[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_8_9[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_10_11[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_12_13[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_14_15[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_16_17[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_18_19[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_20_21[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_22_23[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_24_25[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_26_27[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_28_29[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_30_31[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_32_33[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_MODE[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_DATA[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_DATA_30BIT[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_READ_WRITE_CONTROL[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_NORM_FACTOR[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_COEF_FORMAT[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_MODE[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_MEM_PWR_CTRL[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_FAST_LOAD_SELECT[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_FAST_LOAD_STATUS[MAX_MPCC]; \
- uint32_t MPC_RMCM_CNTL[MAX_MPCC]; \
- uint32_t MPC_RMCM_TEST_DEBUG_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_TEST_DEBUG_DATA[MAX_MPCC]
+ uint32_t MPCC_CONTROL2[MAX_MPCC]
struct dcn42_mpc_shift {
MPC_REG_FIELD_LIST_DCN42(uint8_t);
@@ -884,77 +247,6 @@ void dcn42_mpc_construct(struct dcn42_mpc *mpc401,
void mpc42_init_mpcc(struct mpcc *mpcc, int mpcc_inst);
-/* RMCM */
-void mpc42_program_rmcm_shaper_lut(
- struct mpc *mpc,
- const struct pwl_result_data *rgb,
- uint32_t num,
- uint32_t mpcc_id);
-void mpc42_program_rmcm_shaper_lutb_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id);
-void mpc42_program_rmcm_shaper_luta_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id);
-void mpc42_configure_rmcm_shaper_lut(
- struct mpc *mpc,
- bool is_ram_a,
- uint32_t mpcc_id);
-void mpc42_power_on_rmcm_shaper_3dlut(
- struct mpc *mpc,
- uint32_t mpcc_id,
- bool power_on);
-void mpc42_enable_3dlut_fl(
- struct mpc *mpc,
- bool enable,
- int mpcc_id);
-void mpc42_update_3dlut_fast_load_select(
- struct mpc *mpc,
- int mpcc_id,
- int hubp_idx);
-void mpc42_populate_rmcm_lut(
- struct mpc *mpc,
- const union mcm_lut_params params,
- bool lut_bank_a,
- int mpcc_id);
-void mpc42_program_rmcm_lut_read_write_control(
- struct mpc *mpc,
- const enum MCM_LUT_ID id,
- bool lut_bank_a,
- bool enabled,
- int mpcc_id);
-void mpc42_program_lut_mode(
- struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id);
-void mpc42_program_rmcm_3dlut_size(
- struct mpc *mpc,
- const enum dc_cm_lut_size size,
- int mpcc_id);
-void mpc42_program_rmcm_3dlut_fast_load_bias_scale(
- struct mpc *mpc,
- uint16_t bias,
- uint16_t scale,
- int mpcc_id);
-void mpc42_program_rmcm_bit_depth(
- struct mpc *mpc,
- uint16_t bit_depth,
- int mpcc_id);
-
-void mpc42_set_fl_config(
- struct mpc *mpc,
- struct mpc_fl_3dlut_config *cfg,
- int mpcc_id);
-
-void mpc42_get_rmcm_3dlut_mode(
- struct mpc *mpc,
- int mpcc_id,
- bool *enable,
- bool *lut_bank_a);
-
void mpc42_read_mpcc_state(
struct mpc *mpc,
int mpcc_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
index 2c0b92854a9c..e38582f0a319 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
@@ -111,34 +111,6 @@ static struct mpcc *mpc60_insert_plane(
return new_mpcc;
}
-void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id)
-{
- struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
-
- switch (id) {
- case MCM_LUT_3DLUT:
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
- (!enabled) ? 0 :
- (lut_bank_a) ? 1 : 2);
- break;
-
- case MCM_LUT_SHAPER:
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
-
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL,
- lut_bank_a == true ? 0 : 1);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
- MPC_RMCM_SHAPER_LUT_INDEX, 0);
- break;
- default:
- break;
- }
-}
-
static void mpc60_program_lut_read_write_control(struct mpc *mpc,
const enum MCM_LUT_ID id,
const bool lut_bank_a,
@@ -288,18 +260,6 @@ static const struct mpc_funcs dcn60_mpc_funcs = {
.program_lut_read_write_control = mpc60_program_lut_read_write_control,
.program_lut_mode = mpc60_program_lut_mode,
.get_lut_mode = mpc401_get_lut_mode,
- .rmcm = {
- .enable_3dlut_fl = mpc42_enable_3dlut_fl,
- .update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
- .program_lut_read_write_control = mpc60_program_rmcm_lut_read_write_control,
- .program_lut_mode = mpc42_program_lut_mode,
- .program_3dlut_size = mpc42_program_rmcm_3dlut_size,
- .program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
- .program_bit_depth = mpc42_program_rmcm_bit_depth,
- .power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
- .populate_lut = mpc42_populate_rmcm_lut,
- .get_3dlut_mode = mpc42_get_rmcm_3dlut_mode,
- },
};
void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
@@ -313,6 +273,7 @@ void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
int i;
mpc60->base.ctx = ctx;
+ mpc60->base.inst = 0;
mpc60->base.funcs = &dcn60_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
index 640a322d15c1..44ee84d74104 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
@@ -180,238 +180,6 @@
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_OFFSET_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh), \
SF(MPC_OUT0_CSC_MODE, MPC_OCSC_MODE, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C11_A, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C12_A, mask_sh),\
@@ -463,10 +231,4 @@ void dcn60_mpc_construct(struct dcn60_mpc *mpc401,
const struct dcn60_mpc_mask *mpc_mask,
int num_mpcc,
int num_rmu);
-
-void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc,
- const enum MCM_LUT_ID id,
- bool lut_bank_a,
- bool enabled,
- int mpcc_id);
#endif /* DCN60_MPC_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
index 3ace83e1b50f..ce9cd32b807a 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
@@ -221,6 +221,15 @@ void optc31_set_drr(
}
}
+bool optc3_is_odm_enabled(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t num_segments = 0;
+
+ REG_GET(OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, &num_segments);
+ return num_segments > 0;
+}
+
void optc3_init_odm(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
@@ -503,6 +512,7 @@ static const struct timing_generator_funcs dcn31_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
.optc_read_reg_state = optc31_read_reg_state,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
index 119a954fe3e5..19d90c65a22b 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
@@ -274,6 +274,7 @@ bool optc31_immediate_disable_crtc(struct timing_generator *optc);
void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params);
void optc3_init_odm(struct timing_generator *optc);
+bool optc3_is_odm_enabled(struct timing_generator *optc);
void optc31_read_otg_state(struct timing_generator *optc,
struct dcn_otg_state *s);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
index 7250478a5092..f5faa49680ef 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
@@ -247,6 +247,7 @@ static const struct timing_generator_funcs dcn314_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_odm_bypass = optc314_set_odm_bypass,
.set_odm_combine = optc314_set_odm_combine,
.set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
index 897f857db448..406446e5eae5 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
@@ -614,6 +614,7 @@ static const struct timing_generator_funcs dcn35_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
index fd9c2b6b8b3c..1e4f2051d732 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
@@ -261,6 +261,7 @@ static struct timing_generator_funcs dcn42_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h
index 339372293a98..27d4a96b958f 100644
--- a/drivers/gpu/drm/amd/display/dc/os_types.h
+++ b/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -27,6 +27,7 @@
#ifndef _OS_TYPES_H_
#define _OS_TYPES_H_
+#include <linux/compiler_attributes.h>
#include <linux/slab.h>
#include <linux/kgdb.h>
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
index 2c87e33e909e..79f1b79eacc2 100644
--- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
+++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
@@ -6,6 +6,7 @@
#include "core_types.h"
#include "dcn42_pg_cntl.h"
#include "dccg.h"
+#include "resource.h"
#define TO_DCN_PG_CNTL(pg_cntl)\
container_of(pg_cntl, struct dcn_pg_cntl, base)
@@ -582,7 +583,10 @@ void pg_cntl42_init_pg_status(struct pg_cntl *pg_cntl)
block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, i);
pg_cntl->pg_pipe_res_enable[PG_HUBP][i] = block_enabled;
pg_cntl->pg_pipe_res_enable[PG_DPP][i] = block_enabled;
+ }
+ /* DSC count can be lower than pipe count (e.g. DCN42B has 4 pipes, 3 DSCs) */
+ for (i = 0; i < (unsigned int)pg_cntl->ctx->dc->res_pool->res_cap->num_dsc; i++) {
block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, i);
pg_cntl->pg_pipe_res_enable[PG_DSC][i] = block_enabled;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
index 3903ec22e6af..e5e94e955157 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
@@ -27,6 +27,7 @@
#include "dcn42/dcn42_hubbub.h"
#include "dcn401/dcn401_mpc.h"
#include "dcn42/dcn42_mpc.h"
+#include "dcn42/dcn42_rmcm.h"
#include "dcn35/dcn35_hubp.h"
#include "dcn42/dcn42_hubp.h"
#include "irq/dcn42/irq_service_dcn42.h"
@@ -436,9 +437,7 @@ static struct dcn42_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3), \
- MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0), \
- MPC_RMCM_REG_LIST_DCN42(0), \
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0)
static const struct dcn42_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
@@ -446,6 +445,18 @@ static const struct dcn42_mpc_shift mpc_shift = {
static const struct dcn42_mpc_mask mpc_mask = {
MPC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
#define optc_regs_init(id) \
OPTC_COMMON_REG_LIST_DCN42_RI(id)
@@ -1069,6 +1080,29 @@ static struct mpc *dcn42_mpc_create(
return &mpc401->base;
}
+static struct rmcm *dcn42_rmcm_create(
+ struct dc_context *ctx,
+ int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ return &rmcm42->base;
+}
+
static struct output_pixel_processor *dcn42_opp_create(
struct dc_context *ctx, uint32_t inst)
{
@@ -1548,6 +1582,12 @@ static void dcn42_resource_destruct(struct dcn42_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++) {
+ if (pool->base.rmcm[i] != NULL) {
+ kfree(TO_DCN42_RMCM(pool->base.rmcm[i]));
+ pool->base.rmcm[i] = NULL;
+ }
+ }
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -2330,6 +2370,16 @@ static bool dcn42_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < (unsigned int)pool->base.res_cap->num_rmcm && i < (unsigned int)MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn42_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < (unsigned int)pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn42_dsc_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 66ec56810209..de3bd23f4736 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -31,6 +31,7 @@
#include "dcn42/dcn42_hubbub.h"
#include "dcn401/dcn401_mpc.h"
#include "dcn42/dcn42_mpc.h"
+#include "dcn42/dcn42_rmcm.h"
#include "dcn35/dcn35_hubp.h"
#include "dcn42/dcn42_hubp.h"
#include "irq/dcn42/irq_service_dcn42.h"
@@ -486,9 +487,7 @@ static struct dcn42_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3), \
- MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0), \
- MPC_RMCM_REG_LIST_DCN42(0), \
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0)
static const struct dcn42_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
@@ -496,6 +495,18 @@ static const struct dcn42_mpc_shift mpc_shift = {
static const struct dcn42_mpc_mask mpc_mask = {
MPC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
#define optc_regs_init(id) \
OPTC_COMMON_REG_LIST_DCN42B_RI(id)
@@ -758,6 +769,7 @@ static const struct resource_caps res_cap_dcn42b = {
.num_ddc = 0,
.num_vmid = 16,
.num_mpc_3dlut = 2,
+ .num_rmcm = 2,
.num_dsc = 3,
.num_rmcm = 2,
.num_mpc = 4,
@@ -790,9 +802,13 @@ static const struct dc_debug_options debug_defaults_drv = {
.force_abm_enable = false,
.clock_trace = true,
.disable_pplib_clock_request = false,
- .disable_dpp_power_gate = true,
- .disable_hubp_power_gate = true,
+ .ignore_pg = false,
+ .disable_dpp_power_gate = false,
+ .disable_hubp_power_gate = false,
.disable_optc_power_gate = true,
+ .disable_dsc_power_gate = false,
+ .disable_dio_power_gate = true,
+ .disable_hpo_power_gate = true,
.pipe_split_policy = MPC_SPLIT_AVOID,
.force_single_disp_pipe_split = false,
.disable_dcc = DCC_ENABLE,
@@ -818,14 +834,14 @@ static const struct dc_debug_options debug_defaults_drv = {
}},
.root_clock_optimization = {
.bits = {
- .dpp = false,
- .dsc = false,/*dscclk and dsc pg*/
+ .dpp = true,
+ .dsc = true,/*dscclk and dsc pg*/
.hdmistream = false,
.hdmichar = false,
- .dpstream = false,
- .symclk32_se = false,
- .symclk32_le = false,
- .symclk_fe = false,
+ .dpstream = true,
+ .symclk32_se = true,
+ .symclk32_le = true,
+ .symclk_fe = true,
.physymclk = false,
.dpiasymclk = false,
}
@@ -835,7 +851,8 @@ static const struct dc_debug_options debug_defaults_drv = {
.minimum_z8_residency_time = 1, /* Always allow when other conditions are met */
.support_eDP1_5 = true,
.use_max_lb = true,
- .force_disable_subvp = false,
+ /* SubVP phantom surfaces require MALL, which DCN42B does not have */
+ .force_disable_subvp = true,
.exit_idle_opt_for_cursor_updates = true,
.using_dml2 = true,
.using_dml21 = true,
@@ -854,7 +871,6 @@ static const struct dc_debug_options debug_defaults_drv = {
.min_disp_clk_khz = 50000,
.static_screen_wait_frames = 2,
.disable_z10 = false,
- .ignore_pg = true,
.disable_stutter_for_wm_program = true,
.min_deep_sleep_dcfclk_khz = 8000,
.replay_skip_crtc_disabled = true,
@@ -1128,6 +1144,29 @@ static struct mpc *dcn42b_mpc_create(
return &mpc42b->base;
}
+static struct rmcm *dcn42b_rmcm_create(
+ struct dc_context *ctx,
+ int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ return &rmcm42->base;
+}
+
static struct output_pixel_processor *dcn42b_opp_create(
struct dc_context *ctx, uint32_t inst)
{
@@ -1536,6 +1575,12 @@ static void dcn42b_resource_destruct(struct dcn42b_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++) {
+ if (pool->base.rmcm[i] != NULL) {
+ kfree(TO_DCN42_RMCM(pool->base.rmcm[i]));
+ pool->base.rmcm[i] = NULL;
+ }
+ }
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -1926,8 +1971,6 @@ static struct resource_funcs dcn42b_res_pool_funcs = {
.get_panel_config_defaults = dcn42b_get_panel_config_defaults,
//.get_preferred_eng_id_dpia = dcn42b_get_preferred_eng_id_dpia,
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
- .add_phantom_pipes = dcn32_add_phantom_pipes,
- .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,
.prepare_mcache_programming = dcn42b_prepare_mcache_programming,
.build_pipe_pix_clk_params = dcn42b_build_pipe_pix_clk_params,
.get_power_profile = dcn401_get_power_profile,
@@ -1993,27 +2036,7 @@ static bool dcn42b_resource_construct(
dc->caps.cursor_not_scaled = true;
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
- dc->caps.mall_size_per_mem_channel = 4;
- /* total size = mall per channel * num channels * 1024 * 1024 */
- dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel *
- dc->ctx->dc_bios->vram_info.num_chans * 1048576;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
- dc->caps.cache_line_size = 64;
- dc->caps.cache_num_ways = 16;
-
- /* Calculate the available MALL space */
- dc->caps.max_cab_allocation_bytes =
- dcn32_calc_num_avail_chans_for_mall(dc, dc->ctx->dc_bios->vram_info.num_chans) *
- dc->caps.mall_size_per_mem_channel * 1024 * 1024;
- dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
-
- dc->caps.subvp_fw_processing_delay_us = 15;
- dc->caps.subvp_drr_max_vblank_margin_us = 40;
- dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
- dc->caps.subvp_swath_height_margin_lines = 16;
- dc->caps.subvp_pstate_allow_width_us = 20;
- dc->caps.subvp_vertical_int_margin_us = 30;
- dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin
dc->caps.max_slave_planes = 2;
dc->caps.max_slave_yuv_planes = 2;
@@ -2306,6 +2329,16 @@ static bool dcn42b_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < pool->base.res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn42b_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn42b_dsc_create(ctx, i);
@@ -2391,26 +2424,6 @@ static bool dcn42b_resource_construct(
resource_init_common_dml2_callbacks(dc, &dc->dml2_options);
dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch =
&dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch;
- dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc;
- dc->dml2_options.svp_pstate.callbacks.calculate_mall_ways_from_bytes =
- pool->base.funcs->calculate_mall_ways_from_bytes;
-
- dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us;
- dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us;
- dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us;
- dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines;
-
- dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp;
- dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch;
-
- dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size;
- dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways;
- dc->dml2_options.mall_cfg.max_cab_allocation_bytes =
- dc->caps.max_cab_allocation_bytes;
- dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE;
- dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE;
- dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES;
- dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH;
dc->dml2_options.max_segments_per_hubp = 24;
dc->dml2_options.det_segment_size = DCN42_CRB_SEGMENT_SIZE_KB;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
index 2ccec5ce3b94..171626298e41 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
@@ -19,6 +19,7 @@
#include "dcn321/dcn321_resource.h"
#include "dcn401/dcn401_resource.h"
#include "dcn42/dcn42_resource.h"
+#include "dcn60/dcn60_rmcm.h"
#include "dcn60_resource.h"
#include "dcn10/dcn10_ipp.h"
@@ -464,9 +465,7 @@ static struct dcn60_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\
- MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\
- MPC_RMCM_REG_LIST_DCN42(0),\
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3)
static const struct dcn60_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN6_0(__SHIFT)
@@ -671,11 +670,10 @@ static const struct dc_debug_options debug_defaults_drv = {
.enable_ppt_check = true,
.enable_offload_flip = true,
.enable_stall_recovery = true,
+ .alternate_channel_workaround = true,
}
},
.force_cositing = CHROMA_COSITING_NONE + 1,
- .dml21_disable_pstate_method_mask = 0x20, // disable alt-ch unconditionally until dependencies are ready
-
};
static const struct dc_check_config config_defaults = {
@@ -1695,6 +1693,8 @@ static void dcn60_resource_destruct(struct dcn60_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++)
+ dcn60_rmcm_destroy(&pool->base.rmcm[i]);
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -2288,6 +2288,16 @@ static bool dcn60_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < pool->base.res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn60_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn60_dsc_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/Makefile b/drivers/gpu/drm/amd/display/dc/rmcm/Makefile
new file mode 100644
index 000000000000..9dfc86a850da
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright 2026 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Authors: AMD
+#
+#
+
+ifdef CONFIG_DRM_AMD_DC_FP
+###############################################################################
+# DCN42
+###############################################################################
+RMCM_DCN42 = dcn42_rmcm.o
+
+AMD_DAL_RMCM_DCN42 = $(addprefix $(AMDDALPATH)/dc/rmcm/dcn42/,$(RMCM_DCN42))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_RMCM_DCN42)
+
+###############################################################################
+# DCN60
+###############################################################################
+RMCM_DCN60 = dcn60_rmcm.o
+
+AMD_DAL_RMCM_DCN60 = $(addprefix $(AMDDALPATH)/dc/rmcm/dcn60/,$(RMCM_DCN60))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_RMCM_DCN60)
+endif
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
new file mode 100644
index 000000000000..952f0ade24a5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "reg_helper.h"
+#include "dc.h"
+#include "dcn42_rmcm.h"
+#include "dcn10/dcn10_cm_common.h"
+#include "basics/conversion.h"
+#include "hw_shared.h"
+#include "mpc.h"
+
+#define REG(reg)\
+ rmcm42->rmcm_regs->reg
+
+#define CTX \
+ rmcm42->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+ rmcm42->rmcm_shift->field_name, rmcm42->rmcm_mask->field_name
+
+/* RMCM Shaper functions */
+
+void rmcm42_power_on_shaper_3dlut(
+ struct rmcm *rmcm,
+ uint32_t rmcm_id,
+ bool power_on)
+{
+ uint32_t power_status_shaper = 2;
+ uint32_t power_status_3dlut = 2;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ int max_retries = 10;
+
+ REG_SET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], 0,
+ MPC_RMCM_3DLUT_MEM_PWR_DIS, power_on == true ? 0 : 1);
+ REG_SET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], 0,
+ MPC_RMCM_SHAPER_MEM_PWR_DIS, power_on == true ? 0 : 1);
+ /* wait for memory to fully power up */
+ if (power_on && rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
+ REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
+ REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
+ }
+
+ /*read status is not mandatory, it is just for debugging*/
+ REG_GET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, &power_status_shaper);
+ REG_GET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, &power_status_3dlut);
+
+ if (power_status_shaper != 0 && power_on == true)
+ BREAK_TO_DEBUGGER();
+
+ if (power_status_3dlut != 0 && power_on == true)
+ BREAK_TO_DEBUGGER();
+}
+
+static void rmcm42_configure_shaper_lut(
+ struct rmcm *rmcm,
+ bool is_ram_a,
+ uint32_t rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_B, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_G, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_R[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_R, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0:1);
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_INDEX, 0);
+}
+
+static void rmcm42_program_shaper_luta_settings(
+ struct rmcm *rmcm,
+ const struct pwl_params *params,
+ uint32_t rmcm_id)
+{
+ const struct gamma_curve *curve;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
+
+ curve = params->arr_curve_points;
+ if (curve) {
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_0_1[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_2_3[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_4_5[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_6_7[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_8_9[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_10_11[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_12_13[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_14_15[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_16_17[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_18_19[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_20_21[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_22_23[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_24_25[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_26_27[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_28_29[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_30_31[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_32_33[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+ }
+}
+
+
+static void rmcm42_program_shaper_lutb_settings(
+ struct rmcm *rmcm,
+ const struct pwl_params *params,
+ uint32_t rmcm_id)
+{
+ const struct gamma_curve *curve;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
+
+ curve = params->arr_curve_points;
+ if (curve) {
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_0_1[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_2_3[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_4_5[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_6_7[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_8_9[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_10_11[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_12_13[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_14_15[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_16_17[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_18_19[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_20_21[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_22_23[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_24_25[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_26_27[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_28_29[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_30_31[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_32_33[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+ }
+}
+
+static void rmcm42_program_shaper_lut(
+ struct rmcm *rmcm,
+ const struct pwl_result_data *rgb,
+ uint32_t num,
+ uint32_t rmcm_id)
+{
+ uint32_t i, red, green, blue;
+ uint32_t red_delta, green_delta, blue_delta;
+ uint32_t red_value, green_value, blue_value;
+
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < num; i++) {
+
+ red = rgb[i].red_reg;
+ green = rgb[i].green_reg;
+ blue = rgb[i].blue_reg;
+
+ red_delta = rgb[i].delta_red_reg;
+ green_delta = rgb[i].delta_green_reg;
+ blue_delta = rgb[i].delta_blue_reg;
+
+ red_value = ((red_delta & 0x3ff) << 14) | (red & 0x3fff);
+ green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff);
+ blue_value = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, red_value);
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, green_value);
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, blue_value);
+ }
+}
+
+void rmcm42_update_3dlut_fast_load_select(struct rmcm *rmcm, int rmcm_id, int hubp_idx)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[rmcm_id], 0,
+ MPC_RMCM_3DLUT_FL_SEL,
+ hubp_idx);
+}
+
+static void rmcm42_select_3dlut_ram_mask(
+ struct rmcm *rmcm,
+ uint32_t ram_selection_mask,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, ram_selection_mask);
+ REG_SET(MPC_RMCM_3DLUT_INDEX[rmcm_id], 0, MPC_RMCM_3DLUT_INDEX, 0);
+}
+
+static void rmcm42_set3dlut_ram12(
+ struct rmcm *rmcm,
+ const struct dc_rgb *lut,
+ uint32_t entries,
+ int rmcm_id)
+{
+ uint32_t i, red, green, blue, red1, green1, blue1;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < entries; i += 2) {
+ red = lut[i].red << 4;
+ green = lut[i].green << 4;
+ blue = lut[i].blue << 4;
+ red1 = lut[i + 1].red << 4;
+ green1 = lut[i + 1].green << 4;
+ blue1 = lut[i + 1].blue << 4;
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, red,
+ MPC_RMCM_3DLUT_DATA1, red1);
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, green,
+ MPC_RMCM_3DLUT_DATA1, green1);
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, blue,
+ MPC_RMCM_3DLUT_DATA1, blue1);
+ }
+}
+
+static void rmcm42_set3dlut_ram10(
+ struct rmcm *rmcm,
+ const struct dc_rgb *lut,
+ uint32_t entries,
+ int rmcm_id)
+{
+ uint32_t i, red, green, blue, value;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < entries; i++) {
+ red = lut[i].red;
+ green = lut[i].green;
+ blue = lut[i].blue;
+ value = (red << 20) | (green << 10) | blue;
+
+ REG_SET(MPC_RMCM_3DLUT_DATA_30BIT[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA_30BIT, value);
+ }
+}
+
+void rmcm42_populate_lut(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ const enum dc_lut_mode next_mode = lut_bank_a ? LUT_RAM_A : LUT_RAM_B;
+
+ switch (id) {
+ case MCM_LUT_SHAPER: {
+ const struct pwl_params *lut_shaper = params.pwl;
+
+ if (lut_shaper == NULL)
+ return;
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, true);
+
+ rmcm42_configure_shaper_lut(rmcm, next_mode == LUT_RAM_A, rmcm_id);
+
+ if (next_mode == LUT_RAM_A)
+ rmcm42_program_shaper_luta_settings(rmcm, lut_shaper, rmcm_id);
+ else
+ rmcm42_program_shaper_lutb_settings(rmcm, lut_shaper, rmcm_id);
+
+ rmcm42_program_shaper_lut(
+ rmcm, lut_shaper->rgb_resulted, lut_shaper->hw_points_num, rmcm_id);
+
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ break;
+ }
+ case MCM_LUT_3DLUT: {
+ const struct tetrahedral_params *lut3d = params.lut3d;
+ bool is_17x17x17;
+ bool is_12bits_color_channel;
+ const struct dc_rgb *lut0;
+ const struct dc_rgb *lut1;
+ const struct dc_rgb *lut2;
+ const struct dc_rgb *lut3;
+ int lut_size0;
+ int lut_size;
+
+ if (lut3d == NULL)
+ return;
+
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, true);
+
+ /* Program bit depth before loading data */
+ is_12bits_color_channel = lut3d->use_12bits;
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN,
+ is_12bits_color_channel ? 0 : 1);
+
+ is_17x17x17 = !lut3d->use_tetrahedral_9;
+ is_12bits_color_channel = lut3d->use_12bits;
+ if (is_17x17x17) {
+ lut0 = lut3d->tetrahedral_17.lut0;
+ lut1 = lut3d->tetrahedral_17.lut1;
+ lut2 = lut3d->tetrahedral_17.lut2;
+ lut3 = lut3d->tetrahedral_17.lut3;
+ lut_size0 = sizeof(lut3d->tetrahedral_17.lut0) /
+ sizeof(lut3d->tetrahedral_17.lut0[0]);
+ lut_size = sizeof(lut3d->tetrahedral_17.lut1) /
+ sizeof(lut3d->tetrahedral_17.lut1[0]);
+ } else {
+ lut0 = lut3d->tetrahedral_9.lut0;
+ lut1 = lut3d->tetrahedral_9.lut1;
+ lut2 = lut3d->tetrahedral_9.lut2;
+ lut3 = lut3d->tetrahedral_9.lut3;
+ lut_size0 = sizeof(lut3d->tetrahedral_9.lut0) /
+ sizeof(lut3d->tetrahedral_9.lut0[0]);
+ lut_size = sizeof(lut3d->tetrahedral_9.lut1) /
+ sizeof(lut3d->tetrahedral_9.lut1[0]);
+ }
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x1, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut0, lut_size0, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut0, lut_size0, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x2, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut1, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut1, lut_size, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x4, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut2, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut2, lut_size, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x8, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut3, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut3, lut_size, rmcm_id);
+
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+
+ break;
+ }
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm42_program_lut_read_write_control(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE,
+ (!enabled) ? 0 :
+ (lut_bank_a) ? 1 : 2);
+
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_RAM_SEL,
+ (lut_bank_a) ? 0 : 1);
+ break;
+ case MCM_LUT_SHAPER:
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL,
+ lut_bank_a == true ? 0:1);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0,
+ MPC_RMCM_SHAPER_LUT_INDEX, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+uint32_t rmcm42_get_3dlut_width(
+ const enum dc_cm_lut_size size)
+{
+ uint32_t width = 0;
+
+ switch (size) {
+ case CM_LUT_SIZE_999:
+ width = 1;
+ break;
+ case CM_LUT_SIZE_333333:
+ width = 2;
+ break;
+ case CM_LUT_SIZE_171717:
+ default:
+ width = 0;
+ break;
+ }
+
+ return width;
+}
+
+static void rmcm42_program_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ bool enable,
+ bool lut_bank_a,
+ const enum dc_cm_lut_size size,
+ uint16_t bias,
+ uint16_t scale,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)bias;
+ (void)scale;
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ if (enable) {
+ uint32_t lut_size = rmcm42_get_3dlut_width(size);
+
+ REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE, lut_bank_a ? 1 : 2,
+ MPC_RMCM_3DLUT_SIZE, lut_size);
+
+ /* Default to 12-bit (30BIT_EN=0) for DMA path;
+ * populate_lut overrides for host-load path.
+ */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN, 0);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_SHAPER:
+ if (enable) {
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm42_get_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ int rmcm_id,
+ bool *enable,
+ bool *lut_bank_a)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t lut_mode = 0;
+
+ *enable = false;
+ *lut_bank_a = true;
+
+ switch (id) {
+ case MCM_LUT_SHAPER:
+ REG_GET(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ *lut_bank_a = lut_mode != 2;
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT, return disabled */
+ *enable = false;
+ *lut_bank_a = true;
+ break;
+ case MCM_LUT_3DLUT:
+ default:
+ REG_GET(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ *lut_bank_a = lut_mode != 2;
+ break;
+ }
+}
+
+void rmcm42_get_3dlut_fast_load_status(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t fl_done = 0, fl_soft = 0, fl_hard = 0;
+
+ REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[rmcm_id],
+ MPC_RMCM_3DLUT_FL_DONE, &fl_done,
+ MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &fl_soft,
+ MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &fl_hard);
+
+ *done = (fl_done != 0);
+ *soft_underflow = (fl_soft != 0);
+ *hard_underflow = (fl_hard != 0);
+}
+
+void rmcm42_read_state(struct rmcm *rmcm, int rmcm_inst, struct rmcm_state *s)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ /* RMCM 3DLUT Status */
+ REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[rmcm_inst], MPC_RMCM_3DLUT_MEM_PWR_FORCE, &s->regs.rmcm_3dlut_mem_pwr_force,
+ MPC_RMCM_3DLUT_MEM_PWR_DIS, &s->regs.rmcm_3dlut_mem_pwr_dis,
+ MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, &s->regs.rmcm_3dlut_mem_pwr_mode,
+ MPC_RMCM_3DLUT_MEM_PWR_STATE, &s->regs.rmcm_3dlut_mem_pwr_state);
+
+ REG_GET_3(MPC_RMCM_3DLUT_MODE[rmcm_inst], MPC_RMCM_3DLUT_SIZE, &s->regs.rmcm_3dlut_size,
+ MPC_RMCM_3DLUT_MODE, &s->regs.rmcm_3dlut_mode,
+ MPC_RMCM_3DLUT_MODE_CURRENT, &s->regs.rmcm_3dlut_mode_cur);
+
+ REG_GET_4(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_inst], MPC_RMCM_3DLUT_READ_SEL, &s->regs.rmcm_3dlut_read_sel,
+ MPC_RMCM_3DLUT_30BIT_EN, &s->regs.rmcm_3dlut_30bit_en,
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, &s->regs.rmcm_3dlut_wr_en_mask,
+ MPC_RMCM_3DLUT_RAM_SEL, &s->regs.rmcm_3dlut_ram_sel);
+
+ REG_GET(MPC_RMCM_3DLUT_OUT_NORM_FACTOR[rmcm_inst], MPC_RMCM_3DLUT_OUT_NORM_FACTOR, &s->regs.rmcm_3dlut_out_norm_factor);
+
+ REG_GET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[rmcm_inst], MPC_RMCM_3DLUT_FL_SEL, &s->regs.rmcm_3dlut_fl_sel);
+
+ REG_GET_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[rmcm_inst], MPC_RMCM_3DLUT_OUT_OFFSET_R, &s->regs.rmcm_3dlut_out_offset_r,
+ MPC_RMCM_3DLUT_OUT_SCALE_R, &s->regs.rmcm_3dlut_out_scale_r);
+
+ REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[rmcm_inst], MPC_RMCM_3DLUT_FL_DONE, &s->regs.rmcm_3dlut_fl_done,
+ MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &s->regs.rmcm_3dlut_fl_soft_underflow,
+ MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &s->regs.rmcm_3dlut_fl_hard_underflow);
+
+ /* RMCM Shaper Status */
+ REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[rmcm_inst], MPC_RMCM_SHAPER_MEM_PWR_FORCE, &s->regs.rmcm_shaper_mem_pwr_force,
+ MPC_RMCM_SHAPER_MEM_PWR_DIS, &s->regs.rmcm_shaper_mem_pwr_dis,
+ MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, &s->regs.rmcm_shaper_mem_pwr_mode,
+ MPC_RMCM_SHAPER_MEM_PWR_STATE, &s->regs.rmcm_shaper_mem_pwr_state);
+
+ REG_GET_2(MPC_RMCM_SHAPER_CONTROL[rmcm_inst], MPC_RMCM_SHAPER_LUT_MODE, &s->regs.rmcm_shaper_lut_mode,
+ MPC_RMCM_SHAPER_MODE_CURRENT, &s->regs.rmcm_shaper_mode_cur);
+
+ REG_GET_2(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_inst], MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, &s->regs.rmcm_shaper_lut_write_en_mask,
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, &s->regs.rmcm_shaper_lut_write_sel);
+
+ REG_GET(MPC_RMCM_SHAPER_OFFSET_B[rmcm_inst], MPC_RMCM_SHAPER_OFFSET_B, &s->regs.rmcm_shaper_offset_b);
+
+ REG_GET(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_inst], MPC_RMCM_SHAPER_SCALE_B, &s->regs.rmcm_shaper_scale_b);
+
+ REG_GET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[rmcm_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, &s->regs.rmcm_shaper_rama_exp_region_start_b,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, &s->regs.rmcm_shaper_rama_exp_region_start_seg_b);
+
+ REG_GET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[rmcm_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, &s->regs.rmcm_shaper_rama_exp_region_end_b,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, &s->regs.rmcm_shaper_rama_exp_region_end_base_b);
+
+ REG_GET(MPC_RMCM_CNTL[rmcm_inst], MPC_RMCM_CNTL, &s->regs.rmcm_cntl);
+}
+
+/*
+ * rmcm42_connect_mpcc() - Program RMCM to MPCC routing mux
+ * @rmcm: RMCM instance
+ * @rmcm_id: RMCM hardware index
+ * @mpcc_id: MPCC to connect (0-3), or RMCM_MPCC_ID_NONE to disconnect
+ *
+ * Programs MPC_RMCM_CNTL to route the specified MPCC to this RMCM instance,
+ * allowing any MPCC[x] to RMCM[y] mapping.
+ */
+void rmcm42_connect_mpcc(struct rmcm *rmcm, int rmcm_id, int mpcc_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_CNTL[rmcm_id], MPC_RMCM_CNTL, mpcc_id);
+
+ rmcm->mpcc_id = mpcc_id;
+}
+
+const struct rmcm_funcs dcn42_rmcm_funcs = {
+ .get_lut_mode = rmcm42_get_lut_mode,
+ .program_lut_mode = rmcm42_program_lut_mode,
+ .populate_lut = rmcm42_populate_lut,
+ .program_lut_read_write_control = rmcm42_program_lut_read_write_control,
+ .update_3dlut_fast_load_select = rmcm42_update_3dlut_fast_load_select,
+ .get_3dlut_fast_load_status = rmcm42_get_3dlut_fast_load_status,
+ .read_rmcm_state = rmcm42_read_state,
+ .connect_mpcc = rmcm42_connect_mpcc,
+};
+
+void dcn42_rmcm_construct(
+ struct dcn42_rmcm *rmcm42,
+ struct dc_context *ctx,
+ const struct dcn42_rmcm_registers *regs,
+ const struct dcn42_rmcm_shift *shift,
+ const struct dcn42_rmcm_mask *mask,
+ int inst)
+{
+ rmcm42->base.ctx = ctx;
+ rmcm42->base.inst = inst;
+ rmcm42->base.mpcc_id = RMCM_MPCC_ID_UNKNOWN;
+ rmcm42->base.funcs = &dcn42_rmcm_funcs;
+ rmcm42->rmcm_regs = regs;
+ rmcm42->rmcm_shift = shift;
+ rmcm42->rmcm_mask = mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
new file mode 100644
index 000000000000..caffc14fab05
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
@@ -0,0 +1,717 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_DCN42_H__
+#define __DC_RMCM_DCN42_H__
+
+#include "rmcm.h"
+
+#define TO_DCN42_RMCM(rmcm_base) \
+ container_of(rmcm_base, struct dcn42_rmcm, base)
+
+#define MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(mask_sh) \
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_RAM_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh)
+#define MPC_RMCM_REG_LIST_DCN42(inst)\
+ SRII(MPC_RMCM_SHAPER_CONTROL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_MODE, MPC_RMCM, inst), /*TODO: may need to add other 3DLUT regs*/\
+ SRII(MPC_RMCM_3DLUT_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_DATA, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_CNTL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM, inst)
+
+#define MPC_RMCM_REG_FIELD_LIST_DCN42(type) \
+ type MPC_RMCM_SHAPER_LUT_MODE;\
+ type MPC_RMCM_SHAPER_MODE_CURRENT;\
+ type MPC_RMCM_SHAPER_OFFSET_R;\
+ type MPC_RMCM_SHAPER_OFFSET_G;\
+ type MPC_RMCM_SHAPER_OFFSET_B;\
+ type MPC_RMCM_SHAPER_SCALE_R;\
+ type MPC_RMCM_SHAPER_SCALE_G;\
+ type MPC_RMCM_SHAPER_SCALE_B;\
+ type MPC_RMCM_SHAPER_LUT_INDEX;\
+ type MPC_RMCM_SHAPER_LUT_DATA;\
+ type MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK;\
+ type MPC_RMCM_SHAPER_LUT_WRITE_SEL; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS;\
+ type MPC_RMCM_3DLUT_MODE;\
+ type MPC_RMCM_3DLUT_SIZE;\
+ type MPC_RMCM_3DLUT_MODE_CURRENT;\
+ type MPC_RMCM_3DLUT_INDEX; \
+ type MPC_RMCM_3DLUT_DATA0; \
+ type MPC_RMCM_3DLUT_DATA1; \
+ type MPC_RMCM_3DLUT_DATA_30BIT; \
+ type MPC_RMCM_3DLUT_WRITE_EN_MASK;\
+ type MPC_RMCM_3DLUT_RAM_SEL;\
+ type MPC_RMCM_3DLUT_30BIT_EN;\
+ type MPC_RMCM_3DLUT_READ_SEL;\
+ type MPC_RMCM_3DLUT_OUT_NORM_FACTOR;\
+ type MPC_RMCM_3DLUT_OUT_OFFSET_R;\
+ type MPC_RMCM_3DLUT_OUT_SCALE_R; \
+ type MPC_RMCM_3DLUT_OUT_OFFSET_G; \
+ type MPC_RMCM_3DLUT_OUT_SCALE_G; \
+ type MPC_RMCM_3DLUT_OUT_OFFSET_B; \
+ type MPC_RMCM_3DLUT_OUT_SCALE_B;\
+ type MPC_RMCM_GAMUT_REMAP_COEF_FORMAT;\
+ type MPC_RMCM_GAMUT_REMAP_MODE;\
+ type MPC_RMCM_GAMUT_REMAP_MODE_CURRENT;\
+ type MPC_RMCM_GAMUT_REMAP_C11_A;\
+ type MPC_RMCM_GAMUT_REMAP_C12_A;\
+ type MPC_RMCM_GAMUT_REMAP_C13_A; \
+ type MPC_RMCM_GAMUT_REMAP_C14_A; \
+ type MPC_RMCM_GAMUT_REMAP_C21_A; \
+ type MPC_RMCM_GAMUT_REMAP_C22_A; \
+ type MPC_RMCM_GAMUT_REMAP_C23_A;\
+ type MPC_RMCM_GAMUT_REMAP_C24_A;\
+ type MPC_RMCM_GAMUT_REMAP_C31_A;\
+ type MPC_RMCM_GAMUT_REMAP_C32_A;\
+ type MPC_RMCM_GAMUT_REMAP_C33_A;\
+ type MPC_RMCM_GAMUT_REMAP_C34_A;\
+ type MPC_RMCM_GAMUT_REMAP_C11_B;\
+ type MPC_RMCM_GAMUT_REMAP_C12_B;\
+ type MPC_RMCM_GAMUT_REMAP_C13_B; \
+ type MPC_RMCM_GAMUT_REMAP_C14_B; \
+ type MPC_RMCM_GAMUT_REMAP_C21_B; \
+ type MPC_RMCM_GAMUT_REMAP_C22_B; \
+ type MPC_RMCM_GAMUT_REMAP_C23_B;\
+ type MPC_RMCM_GAMUT_REMAP_C24_B;\
+ type MPC_RMCM_GAMUT_REMAP_C31_B;\
+ type MPC_RMCM_GAMUT_REMAP_C32_B;\
+ type MPC_RMCM_GAMUT_REMAP_C33_B;\
+ type MPC_RMCM_GAMUT_REMAP_C34_B;\
+ type MPC_RMCM_SHAPER_MEM_PWR_FORCE; \
+ type MPC_RMCM_SHAPER_MEM_PWR_DIS; \
+ type MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE; \
+ type MPC_RMCM_3DLUT_MEM_PWR_FORCE;\
+ type MPC_RMCM_3DLUT_MEM_PWR_DIS;\
+ type MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE;\
+ type MPC_RMCM_SHAPER_MEM_PWR_STATE;\
+ type MPC_RMCM_3DLUT_MEM_PWR_STATE;\
+ type MPC_RMCM_3DLUT_FL_SEL;\
+ type MPC_RMCM_3DLUT_FL_DONE; \
+ type MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW; \
+ type MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW; \
+ type MPC_RMCM_CNTL; \
+ type MPC_RMCM_TEST_DEBUG_INDEX;\
+ type MPC_RMCM_TEST_DEBUG_WRITE_EN;\
+ type MPC_RMCM_TEST_DEBUG_DATA
+
+#define MPC_RMCM_REG_VARIABLE_LIST_DCN42 \
+ uint32_t MPC_RMCM_SHAPER_CONTROL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_SCALE_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_SCALE_G_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_DATA[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_0_1[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_2_3[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_4_5[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_6_7[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_8_9[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_10_11[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_12_13[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_14_15[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_16_17[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_18_19[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_20_21[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_22_23[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_24_25[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_26_27[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_28_29[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_30_31[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_32_33[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_0_1[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_2_3[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_4_5[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_6_7[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_8_9[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_10_11[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_12_13[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_14_15[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_16_17[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_18_19[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_20_21[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_22_23[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_24_25[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_26_27[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_28_29[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_30_31[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_32_33[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_MODE[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_DATA[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_DATA_30BIT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_READ_WRITE_CONTROL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_NORM_FACTOR[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_COEF_FORMAT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_MODE[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_MEM_PWR_CTRL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_FAST_LOAD_SELECT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_FAST_LOAD_STATUS[MAX_RMCM]; \
+ uint32_t MPC_RMCM_CNTL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_TEST_DEBUG_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_TEST_DEBUG_DATA[MAX_RMCM]
+
+struct dcn42_rmcm_shift {
+ MPC_RMCM_REG_FIELD_LIST_DCN42(uint8_t);
+};
+
+struct dcn42_rmcm_mask {
+ MPC_RMCM_REG_FIELD_LIST_DCN42(uint32_t);
+};
+
+struct dcn42_rmcm_registers {
+ MPC_RMCM_REG_VARIABLE_LIST_DCN42;
+};
+
+struct dcn42_rmcm {
+ struct rmcm base;
+ const struct dcn42_rmcm_registers *rmcm_regs;
+ const struct dcn42_rmcm_shift *rmcm_shift;
+ const struct dcn42_rmcm_mask *rmcm_mask;
+};
+
+void dcn42_rmcm_construct(
+ struct dcn42_rmcm *rmcm42,
+ struct dc_context *ctx,
+ const struct dcn42_rmcm_registers *regs,
+ const struct dcn42_rmcm_shift *shift,
+ const struct dcn42_rmcm_mask *mask,
+ int inst);
+
+/*
+ * Register-programming helpers shared with the DCN60 RMCM component. They are bank-count
+ * agnostic (LUT data, power, fast load, MPCC routing), so the single-SRAM DCN60 variant
+ * only overrides bank selection.
+ */
+void rmcm42_power_on_shaper_3dlut(struct rmcm *rmcm, uint32_t rmcm_id, bool power_on);
+uint32_t rmcm42_get_3dlut_width(const enum dc_cm_lut_size size);
+void rmcm42_populate_lut(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id);
+void rmcm42_update_3dlut_fast_load_select(struct rmcm *rmcm, int rmcm_id, int hubp_idx);
+void rmcm42_get_3dlut_fast_load_status(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow);
+void rmcm42_read_state(struct rmcm *rmcm, int rmcm_inst, struct rmcm_state *s);
+void rmcm42_connect_mpcc(struct rmcm *rmcm, int rmcm_id, int mpcc_id);
+
+#endif // __DC_RMCM_DCN42_H__
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
new file mode 100644
index 000000000000..df4d6476d70a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dm_services.h"
+#include "dc.h"
+#include "reg_helper.h"
+
+#include "dcn/dcn_6_0_0_offset.h"
+#include "dcn/dcn_6_0_0_sh_mask.h"
+
+#include "dcn60_rmcm.h"
+
+#define SF(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+/* DCN60 renamed MPC_RMCM_3DLUT_RAM_SEL to MPC_RMCM_3DLUT_READ_SEL */
+#define MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_RAM_SEL__SHIFT \
+ MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_READ_SEL__SHIFT
+#define MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_RAM_SEL_MASK \
+ MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_READ_SEL_MASK
+
+/* Resource-level macros needed by MPC_RMCM_REG_LIST_DCN42 */
+#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
+
+#define BASE(seg) BASE_INNER(seg)
+
+#define SRII(reg_name, block, id)\
+ REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
+#define REG(reg)\
+ rmcm42->rmcm_regs->reg
+
+#define CTX \
+ rmcm42->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+ rmcm42->rmcm_shift->field_name, rmcm42->rmcm_mask->field_name
+
+/*
+ * DCN60 RMCM LUT-bank programming (single-SRAM variant).
+ *
+ * DCN60 has one LUT SRAM per RMCM instance instead of the DCN42 A/B pair, and the 3DLUT
+ * read/write-control RAM select was renamed RAM_SEL -> READ_SEL. These overrides always
+ * target bank A and ignore lut_bank_a, so nothing can select a bank that does not exist.
+ * Everything bank-agnostic (LUT upload, fast load, power, MPCC routing) is reused from the
+ * DCN42 rmcm42_* helpers.
+ */
+static void rmcm60_get_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ int rmcm_id,
+ bool *enable,
+ bool *lut_bank_a)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t lut_mode = 0;
+
+ *enable = false;
+ *lut_bank_a = true; /* single SRAM: always bank A */
+
+ switch (id) {
+ case MCM_LUT_SHAPER:
+ REG_GET(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT, return disabled */
+ *enable = false;
+ break;
+ case MCM_LUT_3DLUT:
+ default:
+ REG_GET(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ break;
+ }
+}
+
+static void rmcm60_program_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ bool enable,
+ bool lut_bank_a,
+ const enum dc_cm_lut_size size,
+ uint16_t bias,
+ uint16_t scale,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)bias;
+ (void)scale;
+ (void)lut_bank_a; /* single SRAM: always bank A (mode 1) */
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ if (enable) {
+ uint32_t lut_size = rmcm42_get_3dlut_width(size);
+
+ REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE, 1,
+ MPC_RMCM_3DLUT_SIZE, lut_size);
+
+ /* Default to 12-bit (30BIT_EN=0) for DMA path;
+ * populate_lut overrides for host-load path.
+ */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN, 0);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_SHAPER:
+ if (enable) {
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 1);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm60_program_lut_read_write_control(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)lut_bank_a; /* single SRAM: always bank A */
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE,
+ enabled ? 1 : 0);
+
+ /* DCN60 renamed RAM_SEL -> READ_SEL; single bank -> always 0 */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_RAM_SEL, 0);
+ break;
+ case MCM_LUT_SHAPER:
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, 0);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0,
+ MPC_RMCM_SHAPER_LUT_INDEX, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+/* DCN60 has no RAM_SEL - it became READ_SEL, which the reused DCN42 read_state maps onto
+ * via the compat macro. Clear the duplicate so the reported state stays unambiguous.
+ */
+static void rmcm60_read_state(struct rmcm *rmcm, int rmcm_inst,
+ struct rmcm_state *s)
+{
+ rmcm42_read_state(rmcm, rmcm_inst, s);
+ s->regs.rmcm_3dlut_ram_sel = 0;
+}
+
+static const struct rmcm_funcs dcn60_rmcm_funcs = {
+ .get_lut_mode = rmcm60_get_lut_mode,
+ .program_lut_mode = rmcm60_program_lut_mode,
+ .populate_lut = rmcm42_populate_lut,
+ .program_lut_read_write_control = rmcm60_program_lut_read_write_control,
+ .update_3dlut_fast_load_select = rmcm42_update_3dlut_fast_load_select,
+ .get_3dlut_fast_load_status = rmcm42_get_3dlut_fast_load_status,
+ .read_rmcm_state = rmcm60_read_state,
+ .connect_mpcc = rmcm42_connect_mpcc,
+};
+
+struct rmcm *dcn60_rmcm_create(struct dc_context *ctx, int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ /* Override the DCN42 defaults with the DCN60 single-SRAM LUT-bank ops. */
+ rmcm42->base.funcs = &dcn60_rmcm_funcs;
+
+ return &rmcm42->base;
+}
+
+void dcn60_rmcm_destroy(struct rmcm **rmcm)
+{
+ if (*rmcm) {
+ kfree(TO_DCN42_RMCM(*rmcm));
+ *rmcm = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
new file mode 100644
index 000000000000..8a8b2db2762a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_DCN60_H__
+#define __DC_RMCM_DCN60_H__
+
+#include "dcn42/dcn42_rmcm.h"
+
+struct rmcm *dcn60_rmcm_create(struct dc_context *ctx, int inst);
+
+void dcn60_rmcm_destroy(struct rmcm **rmcm);
+
+#endif /* __DC_RMCM_DCN60_H__ */
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index d8a18cd97811..a5222ffc8ab6 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -1073,7 +1073,7 @@ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_t
* DMUB_STATUS_OK - success
* DMUB_STATUS_INVALID - unspecified error
*/
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd);
+enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, const union dmub_rb_cmd *cmd);
/**
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index 587d26c742cd..dd868e38e0b0 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -1385,7 +1385,7 @@ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_t
dmub->power_state = dmub_srv_power_state;
}
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd)
+enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, const union dmub_rb_cmd *cmd)
{
uint64_t num_pending = 0;
@@ -1411,7 +1411,10 @@ enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_c
/* clear last rsp ack and send message */
dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack(dmub);
- dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, cmd);
+ /* hw_funcs signature is not const as some ASIC variants may reuse the
+ * buffer; send_reg_inbox0_cmd_msg implementations only read from cmd.
+ */
+ dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, (union dmub_rb_cmd *)cmd);
dmub->reg_inbox0.num_submitted++;
dmub->reg_inbox0.is_pending = true;
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
index 5d1275b7cd46..25a0c96ac754 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
@@ -375,6 +375,9 @@ bool mod_power_replay_set_coasting_vtotal(struct mod_power *mod_power,
void mod_power_replay_residency(const struct dc_stream_state *stream,
unsigned int *residency, const bool is_start, const bool is_alpm);
+bool mod_power_replay_get_cumulative_residency(const struct dc_stream_state *stream,
+ uint32_t *residency_milli_pct);
+
bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power,
const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal,
bool is_ultra_sleep_mode, uint16_t frame_skip_number);
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_replay.c b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
index 31d9cb3a12ba..7861e46c612d 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_replay.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
@@ -761,6 +761,19 @@ void mod_power_replay_residency(const struct dc_stream_state *stream,
link->dc->link_srv->edp_replay_residency(link, residency, is_start, mode);
}
+bool mod_power_replay_get_cumulative_residency(const struct dc_stream_state *stream,
+ uint32_t *residency_milli_pct)
+{
+ const struct dc_link *link = dc_stream_get_link(stream);
+
+ if (!link || !link->dc || !link->dc->link_srv)
+ return false;
+
+ return link->dc->link_srv->edp_replay_get_cumulative_residency(
+ link, residency_milli_pct);
+}
+
+
bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power,
const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal,
bool is_ultra_sleep_mode, uint16_t frame_skip_number)
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 01c2631bbdff..d749669f8e6d 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -343,6 +343,7 @@ struct kfd2kgd_calls {
int (*hqd_sdma_get_counter)(struct amdgpu_device *adev,
void *mqd, uint32_t num_sdma_queues_per_eng,
uint64_t *val);
+ void (*hqd_gfx_clean_fault)(struct amdgpu_device *adev);
};
#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
index 4b796d60b03d..3217ad3c1d17 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
@@ -1025,6 +1025,9 @@ int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctr
if (!psmu_info)
return -EINVAL;
+ if (psmu_info->ucSclkEntryNum > MAX_SCLK_RANGE)
+ return -EINVAL;
+
for (i = 0; i < psmu_info->ucSclkEntryNum; i++) {
table->entry[i].ucVco_setting = psmu_info->asSclkFcwRangeEntry[i].ucVco_setting;
table->entry[i].ucPostdiv = psmu_info->asSclkFcwRangeEntry[i].ucPostdiv;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index a29e76b03476..6beafabf1306 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -3077,7 +3077,7 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu,
return ret;
}
}
- return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
+ return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
} else if (smu->od_enabled) {
ret = smu_v13_0_set_ppt_limit(smu, limit_type, msg_limit);
if (ret)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
index 0033453f27e5..1ecf65d402ba 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -25,6 +25,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_smu.h"
#include "smu_v13_0_12_pmfw.h"
#include "smu_v13_0_6_ppt.h"
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index 19bc6ce29da0..ee380488d212 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -25,6 +25,7 @@
#include <linux/firmware.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
#include "amdgpu_smu.h"
#include "atomfirmware.h"
#include "amdgpu_atomfirmware.h"
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 56a5c11bc196..ed99e61f18e1 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -2142,6 +2142,7 @@ static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu)
static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
void **table)
{
+ uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
struct gpu_metrics_v1_3 *gpu_metrics =
(struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
smu, SMU_DRIVER_TABLE_GPU_METRICS);
@@ -2171,6 +2172,8 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
+ if (mp1_ver == IP_VERSION(14, 0, 3) && smu->smc_fw_version >= 0x00685000)
+ gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
index a02167397ce2..982ca34dba8f 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
@@ -830,8 +830,9 @@ int amdgpu_ras_mgr_set_debug_mode(struct amdgpu_device *adev, bool enable)
struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
int ret;
- if (!ras_mgr || !ras_mgr->ras_core || !ras_mgr->ras_is_ready)
- return false;
+ /* this only talks to PMFW, so it does not wait for the RAS block */
+ if (!ras_mgr || !ras_mgr->ras_core)
+ return -EINVAL;
ret = ras_core_set_debug_mode(ras_mgr->ras_core, enable);
if (!ret)
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
index de3da5571ef8..1c5e02de7fca 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
@@ -31,6 +31,7 @@
#include <linux/math64.h>
#include <linux/time.h>
#include "amdgpu.h"
+#include "amdgpu_ip.h"
/* inject address is 52 bits */
#define RAS_UMC_INJECT_ADDR_LIMIT (0x1ULL << 52)
@@ -96,15 +97,13 @@
#define RAS_GET_INST(dev, ip, inst) \
({ \
struct amdgpu_device *adev = (struct amdgpu_device *)dev; \
- adev->ip_map.logical_to_dev_inst ? \
- adev->ip_map.logical_to_dev_inst(adev, ip##_HWIP, inst) : inst; \
+ amdgpu_ip_map_logical_to_dev_inst(&adev->ip_map, ip##_HWIP, inst); \
})
#define RAS_GET_MASK(dev, ip, mask) \
({ \
struct amdgpu_device *adev = (struct amdgpu_device *)dev; \
- (adev->ip_map.logical_to_dev_mask ? \
- adev->ip_map.logical_to_dev_mask(adev, ip##_HWIP, mask) : mask); \
+ amdgpu_ip_map_logical_to_dev_mask(&adev->ip_map, ip##_HWIP, mask); \
})
static inline void *ras_radix_tree_delete_iter(struct radix_tree_root *root, void *iter)
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 8b3f8303a967..5b9c72bf4099 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -1646,6 +1646,38 @@ radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode)
}
}
+/*
+ * Apple's EFI enables the internal eDP panel power sequencer
+ * (LVTMA_PWRSEQ_CNTL) exactly once, at cold boot, and its minimal ATOM tables
+ * never touch it afterwards. Any GPU re-initialisation - S3 resume or a GPU
+ * reset - clears PWRSEQ_EN, so the panel comes back dark on the DCE3.2 iMacs
+ * (iMac10,1 / iMac11,2, RV730). Re-assert PWRSEQ_EN when we find it cleared;
+ * the hardware then runs the DIGON->DE->VARY_BL->BLON power-on sequence itself.
+ * DCE3.2 places the register 0x18 above the R600 offset.
+ *
+ * This is restricted to Apple DCE3.2 parts: the register lives at a different
+ * offset on DCE4+ (which Apple also shipped, e.g. the 2011 MacBook Pro), and
+ * non-Apple boards program the sequencer from their own firmware. The
+ * read-modify-write only fires when the sequencer is actually disabled, so a
+ * lit panel is never disturbed.
+ *
+ * https://gitlab.freedesktop.org/drm/amd/-/issues/5719
+ */
+static void radeon_atom_apple_edp_pwrseq_restore(struct radeon_device *rdev)
+{
+ u32 pwrseq_cntl = R600_LVTMA_PWRSEQ_CNTL + 0x18;
+
+ if (rdev->pdev->subsystem_vendor != PCI_VENDOR_ID_APPLE)
+ return;
+ if (!ASIC_IS_DCE32(rdev) || ASIC_IS_DCE4(rdev))
+ return;
+
+ if (!(RREG32(pwrseq_cntl) & AVIVO_LVTMA_PWRSEQ_EN))
+ WREG32(pwrseq_cntl, AVIVO_LVTMA_PWRSEQ_EN |
+ AVIVO_LVTMA_SYNCEN_OVRD |
+ AVIVO_LVTMA_DIGON);
+}
+
static void
radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
{
@@ -1711,6 +1743,10 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
}
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ /* restore the panel power sequencer on Apple eDP iMacs
+ * that lose it across resume/reset (see helper above)
+ */
+ radeon_atom_apple_edp_pwrseq_restore(rdev);
if (rdev->mode_info.bl_encoder)
atombios_set_backlight_level(radeon_encoder, dig->backlight_level);
else
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 299865569252..8e9402b8811b 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -191,7 +191,7 @@ static int radeon_fence_check_signaled(wait_queue_entry_t *wait,
* @ring: ring index the fence is associated with
*
* Checks the current fence value and calculates the last
- * signalled fence value. Returns true if activity occured
+ * signalled fence value. Returns true if activity occurred
* on the ring, and the fence_queue should be waken up.
*/
static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
@@ -262,7 +262,7 @@ static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
* @work: delayed work item
*
* Checks for fence activity and if there is none probe
- * the hardware if a lockup occured.
+ * the hardware if a lockup occurred.
*/
static void radeon_fence_check_lockup(struct work_struct *work)
{