summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorRodrigo Vivi <rodrigo.vivi@intel.com>2026-01-07 16:49:20 -0500
committerRodrigo Vivi <rodrigo.vivi@intel.com>2026-01-07 16:49:20 -0500
commit3f0e3af4688deb797232c6ef7b45147601d9000d (patch)
tree8cbae54b10271e78e3f26aa541d089120ca52450 /drivers/gpu
parent7c0c19c076ffe84b8bcd5f927eb47452837f2c99 (diff)
parent59260fe5821ad108d0fda8a4a4fe0448e9821f27 (diff)
downloadlinux-3f0e3af4688deb797232c6ef7b45147601d9000d.tar.gz
linux-3f0e3af4688deb797232c6ef7b45147601d9000d.zip
Merge drm/drm-next into drm-xe-next
Bring some drm-scheduler patches to Xe. Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Kconfig199
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v6_0.c35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c35
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c37
-rw-r--r--drivers/gpu/drm/ast/ast_cursor.c83
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c86
-rw-r--r--drivers/gpu/drm/display/drm_dp_helper.c103
-rw-r--r--drivers/gpu/drm/display/drm_dp_mst_topology.c3
-rw-r--r--drivers/gpu/drm/drm_atomic.c1
-rw-r--r--drivers/gpu/drm/drm_bridge.c62
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c108
-rw-r--r--drivers/gpu/drm/drm_gem.c212
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c84
-rw-r--r--drivers/gpu/drm/drm_panic.c75
-rw-r--r--drivers/gpu/drm/drm_plane.c4
-rw-r--r--drivers/gpu/drm/drm_syncobj.c65
-rw-r--r--drivers/gpu/drm/drm_vblank.c52
-rw-r--r--drivers/gpu/drm/hyperv/Kconfig14
-rw-r--r--drivers/gpu/drm/i915/Makefile23
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.c5
-rw-r--r--drivers/gpu/drm/i915/display/g4x_hdmi.c2
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_plane.c9
-rw-r--r--drivers/gpu/drm/i915/display/i9xx_wm.c5
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_alpm.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c76
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_bo.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_bo.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_bw.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_cmtg.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_colorop.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_colorop.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_connector.c14
-rw-r--r--drivers/gpu/drm/i915/display/intel_crt.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc.c31
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_cx0_phy.c927
-rw-r--r--drivers/gpu/drm/i915/display/intel_cx0_phy.h29
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c116
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c102
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h18
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_device.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_device.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_driver.c18
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_irq.c203
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_irq.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c48
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.h48
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_well.c64
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_regs.h23
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_reset.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_rps.c31
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_rps.h21
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h52
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_wa.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_wa.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c234
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux.c16
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c33
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll.c24
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c336
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_dram.c (renamed from drivers/gpu/drm/i915/soc/intel_dram.c)399
-rw-r--r--drivers/gpu/drm/i915/display/intel_dram.h (renamed from drivers/gpu/drm/i915/soc/intel_dram.h)12
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb.c42
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb_buffer.c43
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb_buffer.h13
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsi.h7
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c266
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc_regs.h12
-rw-r--r--drivers/gpu/drm/i915/display/intel_fifo_underrun.c109
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp_gsc.h22
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c78
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug_irq.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_lpe_audio.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_lt_phy.c18
-rw-r--r--drivers/gpu/drm/i915/display/intel_lt_phy.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_lvds.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_setup.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_verify.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_panic.c27
-rw-r--r--drivers/gpu/drm/i915/display/intel_panic.h14
-rw-r--r--drivers/gpu/drm/i915/display/intel_parent.c214
-rw-r--r--drivers/gpu/drm/i915/display/intel_parent.h70
-rw-r--r--drivers/gpu/drm/i915/display/intel_pipe_crc.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane.c96
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane_initial.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.c63
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.h14
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c317
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_rom.c (renamed from drivers/gpu/drm/i915/soc/intel_rom.c)0
-rw-r--r--drivers/gpu/drm/i915/display/intel_rom.h (renamed from drivers/gpu/drm/i915/soc/intel_rom.h)0
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c40
-rw-r--r--drivers/gpu/drm/i915/display/intel_vbt_defs.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_vga.c44
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.c19
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.c8
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object_types.h10
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shmem.c58
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_stolen.c52
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_stolen.h23
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gemfs.c71
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gemfs.h14
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/huge_pages.c15
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.c9
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_print.h5
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.c40
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.h2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_wopcm.c3
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c8
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc.c4
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.c17
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c60
-rw-r--r--drivers/gpu/drm/i915/i915_display_pc8.c31
-rw-r--r--drivers/gpu/drm/i915/i915_display_pc8.h9
-rw-r--r--drivers/gpu/drm/i915/i915_driver.c75
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/i915_edram.c44
-rw-r--r--drivers/gpu/drm/i915/i915_edram.h11
-rw-r--r--drivers/gpu/drm/i915/i915_freq.c111
-rw-r--r--drivers/gpu/drm/i915/i915_freq.h13
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c4
-rw-r--r--drivers/gpu/drm/i915/i915_gmch.c (renamed from drivers/gpu/drm/i915/soc/intel_gmch.c)61
-rw-r--r--drivers/gpu/drm/i915/i915_gmch.h13
-rw-r--r--drivers/gpu/drm/i915/i915_hdcp_gsc.c (renamed from drivers/gpu/drm/i915/display/intel_hdcp_gsc.c)22
-rw-r--r--drivers/gpu/drm/i915/i915_hdcp_gsc.h9
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c16
-rw-r--r--drivers/gpu/drm/i915/i915_irq.h2
-rw-r--r--drivers/gpu/drm/i915/i915_panic.c35
-rw-r--r--drivers/gpu/drm/i915/i915_panic.h9
-rw-r--r--drivers/gpu/drm/i915/i915_params.c5
-rw-r--r--drivers/gpu/drm/i915/i915_params.h1
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c6
-rw-r--r--drivers/gpu/drm/i915/i915_utils.c30
-rw-r--r--drivers/gpu/drm/i915/i915_utils.h22
-rw-r--r--drivers/gpu/drm/i915/intel_clock_gating.c10
-rw-r--r--drivers/gpu/drm/i915/intel_clock_gating.h6
-rw-r--r--drivers/gpu/drm/i915/intel_gvt.c3
-rw-r--r--drivers/gpu/drm/i915/intel_mchbar_regs.h68
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c4
-rw-r--r--drivers/gpu/drm/i915/intel_wakeref.c2
-rw-r--r--drivers/gpu/drm/i915/intel_wakeref.h14
-rw-r--r--drivers/gpu/drm/i915/soc/intel_gmch.h20
-rw-r--r--drivers/gpu/drm/i915/vlv_suspend.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c24
-rw-r--r--drivers/gpu/drm/panel/Kconfig14
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c3
-rw-r--r--drivers/gpu/drm/panel/panel-lg-sw43408.c58
-rw-r--r--drivers/gpu/drm/panel/panel-orisetech-otm8009a.c183
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c179
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c28
-rw-r--r--drivers/gpu/drm/panel/panel-sony-td4353-jdi.c2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.c3
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.h1
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c107
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.h9
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.c257
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.h12
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gpu.c26
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_regs.h10
-rw-r--r--drivers/gpu/drm/panthor/panthor_device.c13
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.c89
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.h9
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw.c8
-rw-r--r--drivers/gpu/drm/panthor/panthor_gem.c258
-rw-r--r--drivers/gpu/drm/panthor/panthor_gem.h8
-rw-r--r--drivers/gpu/drm/panthor/panthor_gpu.c21
-rw-r--r--drivers/gpu/drm/panthor/panthor_mmu.c314
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c254
-rw-r--r--drivers/gpu/drm/pl111/pl111_display.c4
-rw-r--r--drivers/gpu/drm/pl111/pl111_drv.c29
-rw-r--r--drivers/gpu/drm/pl111/pl111_nomadik.c4
-rw-r--r--drivers/gpu/drm/pl111/pl111_nomadik.h4
-rw-r--r--drivers/gpu/drm/pl111/pl111_versatile.c53
-rw-r--r--drivers/gpu/drm/pl111/pl111_versatile.h2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c74
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c23
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h10
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c453
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h34
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c16
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c40
-rw-r--r--drivers/gpu/drm/sitronix/Kconfig48
-rw-r--r--drivers/gpu/drm/sitronix/Makefile3
-rw-r--r--drivers/gpu/drm/sitronix/st7571-i2c.c1003
-rw-r--r--drivers/gpu/drm/sitronix/st7571-spi.c76
-rw-r--r--drivers/gpu/drm/sitronix/st7571.c918
-rw-r--r--drivers/gpu/drm/sitronix/st7571.h91
-rw-r--r--drivers/gpu/drm/sitronix/st7920.c867
-rw-r--r--drivers/gpu/drm/tests/drm_atomic_state_test.c40
-rw-r--r--drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c143
-rw-r--r--drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c64
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c57
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c12
-rw-r--r--drivers/gpu/drm/ttm/ttm_device.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_pool.c26
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c14
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c2
-rw-r--r--drivers/gpu/drm/v3d/Makefile3
-rw-r--r--drivers/gpu/drm/v3d/v3d_bo.c6
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.c2
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.h11
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c21
-rw-r--r--drivers/gpu/drm/v3d/v3d_gemfs.c62
-rw-r--r--drivers/gpu/drm/vgem/Kconfig9
-rw-r--r--drivers/gpu/drm/xe/Makefile19
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h13
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h40
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/gt/intel_gt_types.h11
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_active.h22
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_active_types.h13
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h15
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_irq.h6
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h6
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/i915_vgpu.h18
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h10
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h29
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/soc/intel_dram.h6
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/soc/intel_gmch.h6
-rw-r--r--drivers/gpu/drm/xe/compat-i915-headers/soc/intel_rom.h6
-rw-r--r--drivers/gpu/drm/xe/display/ext/i915_irq.c85
-rw-r--r--drivers/gpu/drm/xe/display/intel_bo.c8
-rw-r--r--drivers/gpu/drm/xe/display/xe_display.c28
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_misc.c16
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_rpm.c3
-rw-r--r--drivers/gpu/drm/xe/display/xe_dsb_buffer.c49
-rw-r--r--drivers/gpu/drm/xe/display/xe_hdcp_gsc.c25
-rw-r--r--drivers/gpu/drm/xe/display/xe_hdcp_gsc.h9
-rw-r--r--drivers/gpu/drm/xe/display/xe_panic.c16
-rw-r--r--drivers/gpu/drm/xe/display/xe_panic.h9
-rw-r--r--drivers/gpu/drm/xe/display/xe_plane_initial.c6
-rw-r--r--drivers/gpu/drm/xe/display/xe_stolen.c62
-rw-r--r--drivers/gpu/drm/xe/display/xe_stolen.h9
-rw-r--r--drivers/gpu/drm/xe/xe_device_types.h7
-rw-r--r--drivers/gpu/drm/xe/xe_hw_fence.c4
269 files changed, 8835 insertions, 4920 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 7e6bc0b3a589..a33b90251530 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -265,164 +265,83 @@ config DRM_SCHED
tristate
depends on DRM
-source "drivers/gpu/drm/sysfb/Kconfig"
+# Separate option as not all DRM drivers use it
+config DRM_PANEL_BACKLIGHT_QUIRKS
+ tristate
-source "drivers/gpu/drm/arm/Kconfig"
+config DRM_LIB_RANDOM
+ bool
+ default n
-source "drivers/gpu/drm/radeon/Kconfig"
+config DRM_PRIVACY_SCREEN
+ bool
+ default n
+# DRM driver Kconfig files, sorted
+source "drivers/gpu/drm/adp/Kconfig"
source "drivers/gpu/drm/amd/amdgpu/Kconfig"
-
-source "drivers/gpu/drm/nouveau/Kconfig"
-
-source "drivers/gpu/drm/nova/Kconfig"
-
-source "drivers/gpu/drm/i915/Kconfig"
-
-source "drivers/gpu/drm/xe/Kconfig"
-
-source "drivers/gpu/drm/kmb/Kconfig"
-
-config DRM_VGEM
- tristate "Virtual GEM provider"
- depends on DRM && MMU
- select DRM_GEM_SHMEM_HELPER
- help
- Choose this option to get a virtual graphics memory manager,
- as used by Mesa's software renderer for enhanced performance.
- If M is selected the module will be called vgem.
-
-source "drivers/gpu/drm/vkms/Kconfig"
-
-source "drivers/gpu/drm/exynos/Kconfig"
-
-source "drivers/gpu/drm/rockchip/Kconfig"
-
-source "drivers/gpu/drm/vmwgfx/Kconfig"
-
-source "drivers/gpu/drm/gma500/Kconfig"
-
-source "drivers/gpu/drm/udl/Kconfig"
-
-source "drivers/gpu/drm/ast/Kconfig"
-
-source "drivers/gpu/drm/mgag200/Kconfig"
-
+source "drivers/gpu/drm/arm/Kconfig"
source "drivers/gpu/drm/armada/Kconfig"
-
+source "drivers/gpu/drm/aspeed/Kconfig"
+source "drivers/gpu/drm/ast/Kconfig"
source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
-
-source "drivers/gpu/drm/renesas/Kconfig"
-
-source "drivers/gpu/drm/sun4i/Kconfig"
-
-source "drivers/gpu/drm/omapdrm/Kconfig"
-
-source "drivers/gpu/drm/tilcdc/Kconfig"
-
-source "drivers/gpu/drm/qxl/Kconfig"
-
-source "drivers/gpu/drm/virtio/Kconfig"
-
-source "drivers/gpu/drm/msm/Kconfig"
-
-source "drivers/gpu/drm/fsl-dcu/Kconfig"
-
-source "drivers/gpu/drm/tegra/Kconfig"
-
-source "drivers/gpu/drm/stm/Kconfig"
-
-source "drivers/gpu/drm/panel/Kconfig"
-
source "drivers/gpu/drm/bridge/Kconfig"
-
-source "drivers/gpu/drm/sti/Kconfig"
-
-source "drivers/gpu/drm/imx/Kconfig"
-
-source "drivers/gpu/drm/ingenic/Kconfig"
-
-source "drivers/gpu/drm/v3d/Kconfig"
-
-source "drivers/gpu/drm/vc4/Kconfig"
-
-source "drivers/gpu/drm/loongson/Kconfig"
-
source "drivers/gpu/drm/etnaviv/Kconfig"
-
+source "drivers/gpu/drm/exynos/Kconfig"
+source "drivers/gpu/drm/fsl-dcu/Kconfig"
+source "drivers/gpu/drm/gma500/Kconfig"
+source "drivers/gpu/drm/gud/Kconfig"
source "drivers/gpu/drm/hisilicon/Kconfig"
-
+source "drivers/gpu/drm/hyperv/Kconfig"
+source "drivers/gpu/drm/i915/Kconfig"
+source "drivers/gpu/drm/imagination/Kconfig"
+source "drivers/gpu/drm/imx/Kconfig"
+source "drivers/gpu/drm/ingenic/Kconfig"
+source "drivers/gpu/drm/kmb/Kconfig"
+source "drivers/gpu/drm/lima/Kconfig"
source "drivers/gpu/drm/logicvc/Kconfig"
-
+source "drivers/gpu/drm/loongson/Kconfig"
+source "drivers/gpu/drm/mcde/Kconfig"
source "drivers/gpu/drm/mediatek/Kconfig"
-
-source "drivers/gpu/drm/mxsfb/Kconfig"
-
source "drivers/gpu/drm/meson/Kconfig"
-
-source "drivers/gpu/drm/tiny/Kconfig"
-
-source "drivers/gpu/drm/pl111/Kconfig"
-
-source "drivers/gpu/drm/tve200/Kconfig"
-
-source "drivers/gpu/drm/xen/Kconfig"
-
-source "drivers/gpu/drm/vboxvideo/Kconfig"
-
-source "drivers/gpu/drm/lima/Kconfig"
-
+source "drivers/gpu/drm/mgag200/Kconfig"
+source "drivers/gpu/drm/msm/Kconfig"
+source "drivers/gpu/drm/mxsfb/Kconfig"
+source "drivers/gpu/drm/nouveau/Kconfig"
+source "drivers/gpu/drm/nova/Kconfig"
+source "drivers/gpu/drm/omapdrm/Kconfig"
+source "drivers/gpu/drm/panel/Kconfig"
source "drivers/gpu/drm/panfrost/Kconfig"
-
source "drivers/gpu/drm/panthor/Kconfig"
-
-source "drivers/gpu/drm/aspeed/Kconfig"
-
-source "drivers/gpu/drm/mcde/Kconfig"
-
-source "drivers/gpu/drm/tidss/Kconfig"
-
-source "drivers/gpu/drm/adp/Kconfig"
-
-source "drivers/gpu/drm/xlnx/Kconfig"
-
-source "drivers/gpu/drm/gud/Kconfig"
-
+source "drivers/gpu/drm/pl111/Kconfig"
+source "drivers/gpu/drm/qxl/Kconfig"
+source "drivers/gpu/drm/radeon/Kconfig"
+source "drivers/gpu/drm/renesas/Kconfig"
+source "drivers/gpu/drm/rockchip/Kconfig"
source "drivers/gpu/drm/sitronix/Kconfig"
-
source "drivers/gpu/drm/solomon/Kconfig"
-
source "drivers/gpu/drm/sprd/Kconfig"
-
-source "drivers/gpu/drm/imagination/Kconfig"
-
+source "drivers/gpu/drm/sti/Kconfig"
+source "drivers/gpu/drm/stm/Kconfig"
+source "drivers/gpu/drm/sun4i/Kconfig"
+source "drivers/gpu/drm/sysfb/Kconfig"
+source "drivers/gpu/drm/tegra/Kconfig"
+source "drivers/gpu/drm/tidss/Kconfig"
+source "drivers/gpu/drm/tilcdc/Kconfig"
+source "drivers/gpu/drm/tiny/Kconfig"
+source "drivers/gpu/drm/tve200/Kconfig"
source "drivers/gpu/drm/tyr/Kconfig"
-
-config DRM_HYPERV
- tristate "DRM Support for Hyper-V synthetic video device"
- depends on DRM && PCI && HYPERV_VMBUS
- select DRM_CLIENT_SELECTION
- select DRM_KMS_HELPER
- select DRM_GEM_SHMEM_HELPER
- help
- This is a KMS driver for Hyper-V synthetic video device. Choose this
- option if you would like to enable drm driver for Hyper-V virtual
- machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so
- that DRM driver is used by default.
-
- If M is selected the module will be called hyperv_drm.
-
-# Separate option as not all DRM drivers use it
-config DRM_PANEL_BACKLIGHT_QUIRKS
- tristate
-
-config DRM_LIB_RANDOM
- bool
- default n
-
-config DRM_PRIVACY_SCREEN
- bool
- default n
+source "drivers/gpu/drm/udl/Kconfig"
+source "drivers/gpu/drm/v3d/Kconfig"
+source "drivers/gpu/drm/vboxvideo/Kconfig"
+source "drivers/gpu/drm/vc4/Kconfig"
+source "drivers/gpu/drm/vgem/Kconfig"
+source "drivers/gpu/drm/virtio/Kconfig"
+source "drivers/gpu/drm/vkms/Kconfig"
+source "drivers/gpu/drm/vmwgfx/Kconfig"
+source "drivers/gpu/drm/xe/Kconfig"
+source "drivers/gpu/drm/xen/Kconfig"
+source "drivers/gpu/drm/xlnx/Kconfig"
endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 58c3ffe707d1..12201b8e99b3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -6613,6 +6613,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
struct amdgpu_hive_info *hive = NULL;
int r = 0;
bool need_emergency_restart = false;
+ /* save the pasid here as the job may be freed before the end of the reset */
+ int pasid = job ? job->pasid : -EINVAL;
/*
* If it reaches here because of hang/timeout and a RAS error is
@@ -6713,8 +6715,12 @@ end_reset:
if (!r) {
struct amdgpu_task_info *ti = NULL;
- if (job)
- ti = amdgpu_vm_get_task_info_pasid(adev, job->pasid);
+ /*
+ * The job may already be freed at this point via the sched tdr workqueue so
+ * use the cached pasid.
+ */
+ if (pasid >= 0)
+ ti = amdgpu_vm_get_task_info_pasid(adev, pasid);
drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE,
ti ? &ti->task : NULL);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 2dfbddcef9ab..848e6b7db482 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -33,6 +33,7 @@
#include <drm/drm_vblank.h>
#include <linux/cc_platform.h>
+#include <linux/console.h>
#include <linux/dynamic_debug.h>
#include <linux/module.h>
#include <linux/mmu_notifier.h>
@@ -2704,7 +2705,9 @@ static int amdgpu_pmops_thaw(struct device *dev)
struct drm_device *drm_dev = dev_get_drvdata(dev);
/* do not resume device if it's normal hibernation */
- if (!pm_hibernate_is_recovering() && !pm_hibernation_mode_is_suspend())
+ if (console_suspend_enabled &&
+ !pm_hibernate_is_recovering() &&
+ !pm_hibernation_mode_is_suspend())
return 0;
return amdgpu_device_resume(drm_dev, true);
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 72ca6538b2e4..61302204e9b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -1838,7 +1838,7 @@ static void dce_v10_0_grph_enable(struct drm_crtc *crtc, bool enable)
static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1855,15 +1855,12 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
bool bypass_lut = false;
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
/* If atomic, assume fb object is pinned & idle & fenced and
* just update base pointers
@@ -1874,13 +1871,11 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
if (unlikely(r != 0))
return r;
- if (!atomic) {
- abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
- r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
- if (unlikely(r != 0)) {
- amdgpu_bo_unreserve(abo);
- return -EINVAL;
- }
+ abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
+ r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
+ if (unlikely(r != 0)) {
+ amdgpu_bo_unreserve(abo);
+ return -EINVAL;
}
fb_location = amdgpu_bo_gpu_offset(abo);
@@ -2068,7 +2063,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
/* set pageflip to happen anywhere in vblank interval */
WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
abo = gem_to_amdgpu_bo(fb->obj[0]);
r = amdgpu_bo_reserve(abo, true);
if (unlikely(r != 0))
@@ -2611,7 +2606,7 @@ static int dce_v10_0_crtc_mode_set(struct drm_crtc *crtc,
amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode);
- dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y);
amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode);
amdgpu_atombios_crtc_scaler_setup(crtc);
dce_v10_0_cursor_reset(crtc);
@@ -2659,14 +2654,7 @@ static bool dce_v10_0_crtc_mode_fixup(struct drm_crtc *crtc,
static int dce_v10_0_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
- return dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-static int dce_v10_0_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- return dce_v10_0_crtc_do_set_base(crtc, fb, x, y, 1);
+ return dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y);
}
static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = {
@@ -2674,7 +2662,6 @@ static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = {
.mode_fixup = dce_v10_0_crtc_mode_fixup,
.mode_set = dce_v10_0_crtc_mode_set,
.mode_set_base = dce_v10_0_crtc_set_base,
- .mode_set_base_atomic = dce_v10_0_crtc_set_base_atomic,
.prepare = dce_v10_0_crtc_prepare,
.commit = dce_v10_0_crtc_commit,
.disable = dce_v10_0_crtc_disable,
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index acc887a58518..8f4b4c2e36b9 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -1876,7 +1876,7 @@ static void dce_v6_0_grph_enable(struct drm_crtc *crtc, bool enable)
static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1892,15 +1892,12 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc,
bool bypass_lut = false;
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
/* If atomic, assume fb object is pinned & idle & fenced and
* just update base pointers
@@ -1911,13 +1908,11 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc,
if (unlikely(r != 0))
return r;
- if (!atomic) {
- abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
- r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
- if (unlikely(r != 0)) {
- amdgpu_bo_unreserve(abo);
- return -EINVAL;
- }
+ abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
+ r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
+ if (unlikely(r != 0)) {
+ amdgpu_bo_unreserve(abo);
+ return -EINVAL;
}
fb_location = amdgpu_bo_gpu_offset(abo);
@@ -2083,7 +2078,7 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc,
/* set pageflip to happen anywhere in vblank interval */
WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
abo = gem_to_amdgpu_bo(fb->obj[0]);
r = amdgpu_bo_reserve(abo, true);
if (unlikely(r != 0))
@@ -2578,7 +2573,7 @@ static int dce_v6_0_crtc_mode_set(struct drm_crtc *crtc,
amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode);
- dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y);
amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode);
amdgpu_atombios_crtc_scaler_setup(crtc);
dce_v6_0_cursor_reset(crtc);
@@ -2626,14 +2621,7 @@ static bool dce_v6_0_crtc_mode_fixup(struct drm_crtc *crtc,
static int dce_v6_0_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
- return dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-static int dce_v6_0_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- return dce_v6_0_crtc_do_set_base(crtc, fb, x, y, 1);
+ return dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y);
}
static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = {
@@ -2641,7 +2629,6 @@ static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = {
.mode_fixup = dce_v6_0_crtc_mode_fixup,
.mode_set = dce_v6_0_crtc_mode_set,
.mode_set_base = dce_v6_0_crtc_set_base,
- .mode_set_base_atomic = dce_v6_0_crtc_set_base_atomic,
.prepare = dce_v6_0_crtc_prepare,
.commit = dce_v6_0_crtc_commit,
.disable = dce_v6_0_crtc_disable,
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 2ccd6aad8dd6..9d1853c41fcd 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -1785,7 +1785,7 @@ static void dce_v8_0_grph_enable(struct drm_crtc *crtc, bool enable)
static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1802,15 +1802,12 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
bool bypass_lut = false;
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
/* If atomic, assume fb object is pinned & idle & fenced and
* just update base pointers
@@ -1821,13 +1818,11 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
if (unlikely(r != 0))
return r;
- if (!atomic) {
- abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
- r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
- if (unlikely(r != 0)) {
- amdgpu_bo_unreserve(abo);
- return -EINVAL;
- }
+ abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
+ r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM);
+ if (unlikely(r != 0)) {
+ amdgpu_bo_unreserve(abo);
+ return -EINVAL;
}
fb_location = amdgpu_bo_gpu_offset(abo);
@@ -1995,7 +1990,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
/* set pageflip to happen anywhere in vblank interval */
WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
abo = gem_to_amdgpu_bo(fb->obj[0]);
r = amdgpu_bo_reserve(abo, true);
if (unlikely(r != 0))
@@ -2537,7 +2532,7 @@ static int dce_v8_0_crtc_mode_set(struct drm_crtc *crtc,
amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode);
- dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y);
amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode);
amdgpu_atombios_crtc_scaler_setup(crtc);
dce_v8_0_cursor_reset(crtc);
@@ -2585,14 +2580,7 @@ static bool dce_v8_0_crtc_mode_fixup(struct drm_crtc *crtc,
static int dce_v8_0_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
- return dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-static int dce_v8_0_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- return dce_v8_0_crtc_do_set_base(crtc, fb, x, y, 1);
+ return dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y);
}
static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = {
@@ -2600,7 +2588,6 @@ static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = {
.mode_fixup = dce_v8_0_crtc_mode_fixup,
.mode_set = dce_v8_0_crtc_mode_set,
.mode_set_base = dce_v8_0_crtc_set_base,
- .mode_set_base_atomic = dce_v8_0_crtc_set_base_atomic,
.prepare = dce_v8_0_crtc_prepare,
.commit = dce_v8_0_crtc_commit,
.disable = dce_v8_0_crtc_disable,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index a085faac9fe1..bb252ec43733 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1987,10 +1987,10 @@ kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node,
return -EINVAL;
}
-static int signal_eviction_fence(struct kfd_process *p)
+static bool signal_eviction_fence(struct kfd_process *p)
{
struct dma_fence *ef;
- int ret;
+ bool ret;
rcu_read_lock();
ef = dma_fence_get_rcu_safe(&p->ef);
@@ -1998,7 +1998,7 @@ static int signal_eviction_fence(struct kfd_process *p)
if (!ef)
return -EINVAL;
- ret = dma_fence_signal(ef);
+ ret = dma_fence_check_and_signal(ef);
dma_fence_put(ef);
return ret;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
index a499449fcb06..d2bc169e84b0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
@@ -312,7 +312,7 @@ void kfd_smi_event_queue_restore(struct kfd_node *node, pid_t pid)
{
kfd_smi_event_add(pid, node, KFD_SMI_EVENT_QUEUE_RESTORE,
KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(), pid,
- node->id, 0));
+ node->id, '0'));
}
void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 4986f12dc9df..0cdd8c74abdf 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -1118,13 +1118,13 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
num_audio++;
}
+ if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) {
+ /*wake AZ from D3 first before access az endpoint*/
+ clk_mgr->funcs->enable_pme_wa(clk_mgr);
+ }
pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
- if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa)
- /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
- clk_mgr->funcs->enable_pme_wa(clk_mgr);
-
link_hwss->enable_audio_packet(pipe_ctx);
if (pipe_ctx->stream_res.audio)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
index ef69898d2cc5..d056e5fd5458 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
@@ -203,12 +203,12 @@ enum dcn35_clk_src_array_id {
NBIO_BASE_INNER(seg)
#define NBIO_SR(reg_name)\
- REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \
- regBIF_BX2_ ## reg_name
+ REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX1_ ## reg_name
#define NBIO_SR_ARR(reg_name, id)\
- REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \
- regBIF_BX2_ ## reg_name
+ REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX1_ ## reg_name
#define bios_regs_init() \
( \
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
index f3c614c4490c..9fab3169069c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
@@ -183,12 +183,12 @@ enum dcn351_clk_src_array_id {
NBIO_BASE_INNER(seg)
#define NBIO_SR(reg_name)\
- REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \
- regBIF_BX2_ ## reg_name
+ REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX1_ ## reg_name
#define NBIO_SR_ARR(reg_name, id)\
- REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \
- regBIF_BX2_ ## reg_name
+ REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX1_ ## reg_name
#define bios_regs_init() \
( \
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index f9b0938c57ea..f2a16dfee599 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -1939,6 +1939,11 @@ int smu_v14_0_od_edit_dpm_table(struct smu_context *smu,
dev_err(smu->adev->dev, "Set soft max sclk failed!");
return ret;
}
+ if (smu->gfx_actual_hard_min_freq != smu->gfx_default_hard_min_freq ||
+ smu->gfx_actual_soft_max_freq != smu->gfx_default_soft_max_freq)
+ smu->user_dpm_profile.user_od = true;
+ else
+ smu->user_dpm_profile.user_od = false;
break;
default:
return -ENOSYS;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index b1bd946d8e30..97414bc39764 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -1514,9 +1514,10 @@ static int smu_v14_0_1_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
- smu->gfx_actual_hard_min_freq = 0;
- smu->gfx_actual_soft_max_freq = 0;
-
+ if (smu->gfx_actual_hard_min_freq == 0)
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ if (smu->gfx_actual_soft_max_freq == 0)
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
return 0;
}
@@ -1526,8 +1527,10 @@ static int smu_v14_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
- smu->gfx_actual_hard_min_freq = 0;
- smu->gfx_actual_soft_max_freq = 0;
+ if (smu->gfx_actual_hard_min_freq == 0)
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ if (smu->gfx_actual_soft_max_freq == 0)
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
return 0;
}
@@ -1665,6 +1668,29 @@ static int smu_v14_0_common_set_mall_enable(struct smu_context *smu)
return ret;
}
+static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
+ smu->gfx_actual_hard_min_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to restore hard min sclk!\n");
+ return ret;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
+ smu->gfx_actual_soft_max_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to restore soft max sclk!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.check_fw_status = smu_v14_0_check_fw_status,
.check_fw_version = smu_v14_0_check_fw_version,
@@ -1688,6 +1714,7 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.mode2_reset = smu_v14_0_0_mode2_reset,
.get_dpm_ultimate_freq = smu_v14_0_common_get_dpm_ultimate_freq,
.set_soft_freq_limited_range = smu_v14_0_0_set_soft_freq_limited_range,
+ .restore_user_od_settings = smu_v14_0_0_restore_user_od_settings,
.od_edit_dpm_table = smu_v14_0_od_edit_dpm_table,
.print_clk_levels = smu_v14_0_0_print_clk_levels,
.force_clk_levels = smu_v14_0_0_force_clk_levels,
diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c
index 2d3ad7610c2e..30b62d3f0151 100644
--- a/drivers/gpu/drm/ast/ast_cursor.c
+++ b/drivers/gpu/drm/ast/ast_cursor.c
@@ -28,6 +28,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include "ast_drv.h"
@@ -181,6 +182,62 @@ static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane,
return 0;
}
+static const u8 *ast_cursor_plane_get_argb4444(struct ast_cursor_plane *ast_cursor_plane,
+ struct drm_shadow_plane_state *shadow_plane_state,
+ const struct drm_rect *clip)
+{
+ struct drm_plane_state *plane_state = &shadow_plane_state->base;
+ struct drm_framebuffer *fb = plane_state->fb;
+ u8 *argb4444 = NULL;
+
+ if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
+ switch (fb->format->format) {
+ case DRM_FORMAT_ARGB4444:
+ if (shadow_plane_state->data[0].is_iomem) {
+ struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = {
+ IOSYS_MAP_INIT_VADDR(ast_cursor_plane->argb4444),
+ };
+ unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
+ AST_HWC_PITCH,
+ };
+
+ drm_fb_memcpy(argb4444_dst, argb4444_dst_pitch,
+ shadow_plane_state->data, fb, clip);
+ argb4444 = argb4444_dst[0].vaddr;
+ } else {
+ argb4444 = shadow_plane_state->data[0].vaddr;
+ }
+ break;
+ case DRM_FORMAT_ARGB8888:
+ {
+ struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = {
+ IOSYS_MAP_INIT_VADDR(ast_cursor_plane->argb4444),
+ };
+ unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
+ AST_HWC_PITCH,
+ };
+
+ drm_fb_argb8888_to_argb4444(argb4444_dst, argb4444_dst_pitch,
+ shadow_plane_state->data, fb, clip,
+ &shadow_plane_state->fmtcnv_state);
+ argb4444 = argb4444_dst[0].vaddr;
+ }
+ break;
+ }
+
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+ } else {
+ /*
+ * Fall back to white square if GEM object is not ready. Gives
+ * the user an indication where the cursor is located.
+ */
+ memset(ast_cursor_plane->argb4444, 0xff, sizeof(ast_cursor_plane->argb4444));
+ argb4444 = ast_cursor_plane->argb4444;
+ }
+
+ return argb4444;
+}
+
static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *state)
{
@@ -205,29 +262,13 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
*/
if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) {
- u8 *argb4444;
+ const u8 *argb4444 = ast_cursor_plane_get_argb4444(ast_cursor_plane,
+ shadow_plane_state,
+ &damage);
- switch (fb->format->format) {
- case DRM_FORMAT_ARGB4444:
- argb4444 = shadow_plane_state->data[0].vaddr;
- break;
- default:
- argb4444 = ast_cursor_plane->argb4444;
- {
- struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = {
- IOSYS_MAP_INIT_VADDR(argb4444),
- };
- unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
- AST_HWC_PITCH,
- };
+ if (argb4444)
+ ast_set_cursor_image(ast, argb4444, fb->width, fb->height);
- drm_fb_argb8888_to_argb4444(argb4444_dst, argb4444_dst_pitch,
- shadow_plane_state->data, fb, &damage,
- &shadow_plane_state->fmtcnv_state);
- }
- break;
- }
- ast_set_cursor_image(ast, argb4444, fb->width, fb->height);
ast_set_cursor_base(ast, dst_off);
}
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index fffb47b62f43..f6736b4457bb 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -406,6 +406,10 @@ static void sn65dsi83_reset_work(struct work_struct *ws)
{
struct sn65dsi83 *ctx = container_of(ws, struct sn65dsi83, reset_work);
int ret;
+ int idx;
+
+ if (!drm_bridge_enter(&ctx->bridge, &idx))
+ return;
/* Reset the pipe */
ret = sn65dsi83_reset_pipe(ctx);
@@ -415,12 +419,18 @@ static void sn65dsi83_reset_work(struct work_struct *ws)
}
if (ctx->irq)
enable_irq(ctx->irq);
+
+ drm_bridge_exit(idx);
}
static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx)
{
unsigned int irq_stat;
int ret;
+ int idx;
+
+ if (!drm_bridge_enter(&ctx->bridge, &idx))
+ return;
/*
* Schedule a reset in case of:
@@ -448,6 +458,8 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx)
schedule_work(&ctx->reset_work);
}
+
+ drm_bridge_exit(idx);
}
static void sn65dsi83_monitor_work(struct work_struct *work)
@@ -470,6 +482,37 @@ static void sn65dsi83_monitor_stop(struct sn65dsi83 *ctx)
cancel_delayed_work_sync(&ctx->monitor_work);
}
+/*
+ * Release resources taken by sn65dsi83_atomic_pre_enable().
+ *
+ * Invoked by sn65dsi83_atomic_disable() normally, or by devres after
+ * sn65dsi83_remove() in case this happens befora atomic_disable.
+ */
+static void sn65dsi83_release_resources(void *data)
+{
+ struct sn65dsi83 *ctx = (struct sn65dsi83 *)data;
+ int ret;
+
+ if (ctx->irq) {
+ /* Disable irq */
+ regmap_write(ctx->regmap, REG_IRQ_EN, 0x0);
+ regmap_write(ctx->regmap, REG_IRQ_GLOBAL, 0x0);
+ } else {
+ /* Stop the polling task */
+ sn65dsi83_monitor_stop(ctx);
+ }
+
+ /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
+ gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+ usleep_range(10000, 11000);
+
+ ret = regulator_disable(ctx->vcc);
+ if (ret)
+ dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret);
+
+ regcache_mark_dirty(ctx->regmap);
+}
+
static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
@@ -485,11 +528,15 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
__le16 le16val;
u16 val;
int ret;
+ int idx;
+
+ if (!drm_bridge_enter(bridge, &idx))
+ return;
ret = regulator_enable(ctx->vcc);
if (ret) {
dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret);
- return;
+ goto err_exit;
}
/* Deassert reset */
@@ -632,7 +679,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret);
/* On failure, disable PLL again and exit. */
regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
- return;
+ goto err_add_action;
}
/* Trigger reset after CSR register update. */
@@ -640,6 +687,11 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
/* Wait for 10ms after soft reset as specified in datasheet */
usleep_range(10000, 12000);
+
+err_add_action:
+ devm_add_action(ctx->dev, sn65dsi83_release_resources, ctx);
+err_exit:
+ drm_bridge_exit(idx);
}
static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
@@ -647,6 +699,10 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
unsigned int pval;
+ int idx;
+
+ if (!drm_bridge_enter(bridge, &idx))
+ return;
/* Clear all errors that got asserted during initialization. */
regmap_read(ctx->regmap, REG_IRQ_STAT, &pval);
@@ -666,32 +722,22 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
/* Use the polling task */
sn65dsi83_monitor_start(ctx);
}
+
+ drm_bridge_exit(idx);
}
static void sn65dsi83_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
- int ret;
+ int idx;
- if (ctx->irq) {
- /* Disable irq */
- regmap_write(ctx->regmap, REG_IRQ_EN, 0x0);
- regmap_write(ctx->regmap, REG_IRQ_GLOBAL, 0x0);
- } else {
- /* Stop the polling task */
- sn65dsi83_monitor_stop(ctx);
- }
-
- /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
- gpiod_set_value_cansleep(ctx->enable_gpio, 0);
- usleep_range(10000, 11000);
+ if (!drm_bridge_enter(bridge, &idx))
+ return;
- ret = regulator_disable(ctx->vcc);
- if (ret)
- dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret);
+ devm_release_action(ctx->dev, sn65dsi83_release_resources, ctx);
- regcache_mark_dirty(ctx->regmap);
+ drm_bridge_exit(idx);
}
static enum drm_mode_status
@@ -1012,7 +1058,7 @@ static void sn65dsi83_remove(struct i2c_client *client)
{
struct sn65dsi83 *ctx = i2c_get_clientdata(client);
- drm_bridge_remove(&ctx->bridge);
+ drm_bridge_unplug(&ctx->bridge);
}
static const struct i2c_device_id sn65dsi83_id[] = {
diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
index f9fdf19de74a..a697cc227e28 100644
--- a/drivers/gpu/drm/display/drm_dp_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
@@ -2705,6 +2705,71 @@ u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
EXPORT_SYMBOL(drm_dp_dsc_sink_bpp_incr);
/**
+ * drm_dp_dsc_slice_count_to_mask() - Convert a slice count to a slice count mask
+ * @slice_count: slice count
+ *
+ * Convert @slice_count to a slice count mask.
+ *
+ * Returns the slice count mask.
+ */
+u32 drm_dp_dsc_slice_count_to_mask(int slice_count)
+{
+ return BIT(slice_count - 1);
+}
+EXPORT_SYMBOL(drm_dp_dsc_slice_count_to_mask);
+
+/**
+ * drm_dp_dsc_sink_slice_count_mask() - Get the mask of valid DSC sink slice counts
+ * @dsc_dpcd: the sink's DSC DPCD capabilities
+ * @is_edp: %true for an eDP sink
+ *
+ * Get the mask of supported slice counts from the sink's DSC DPCD register.
+ *
+ * Returns:
+ * Mask of slice counts supported by the DSC sink:
+ * - > 0: bit#0,1,3,5..,23 set if the sink supports 1,2,4,6..,24 slices
+ * - 0: if the sink doesn't support any slices
+ */
+u32 drm_dp_dsc_sink_slice_count_mask(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
+ bool is_edp)
+{
+ u8 slice_cap1 = dsc_dpcd[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT];
+ u32 mask = 0;
+
+ if (!is_edp) {
+ /* For DP, use values from DSC_SLICE_CAP_1 and DSC_SLICE_CAP2 */
+ u8 slice_cap2 = dsc_dpcd[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT];
+
+ if (slice_cap2 & DP_DSC_24_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(24);
+ if (slice_cap2 & DP_DSC_20_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(20);
+ if (slice_cap2 & DP_DSC_16_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(16);
+ }
+
+ /* DP, eDP v1.5+ */
+ if (slice_cap1 & DP_DSC_12_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(12);
+ if (slice_cap1 & DP_DSC_10_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(10);
+ if (slice_cap1 & DP_DSC_8_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(8);
+ if (slice_cap1 & DP_DSC_6_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(6);
+ /* DP, eDP v1.4+ */
+ if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(4);
+ if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(2);
+ if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK)
+ mask |= drm_dp_dsc_slice_count_to_mask(1);
+
+ return mask;
+}
+EXPORT_SYMBOL(drm_dp_dsc_sink_slice_count_mask);
+
+/**
* drm_dp_dsc_sink_max_slice_count() - Get the max slice count
* supported by the DSC sink.
* @dsc_dpcd: DSC capabilities from DPCD
@@ -2723,43 +2788,7 @@ EXPORT_SYMBOL(drm_dp_dsc_sink_bpp_incr);
u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
bool is_edp)
{
- u8 slice_cap1 = dsc_dpcd[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT];
-
- if (is_edp) {
- /* For eDP, register DSC_SLICE_CAPABILITIES_1 gives slice count */
- if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK)
- return 4;
- if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK)
- return 2;
- if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK)
- return 1;
- } else {
- /* For DP, use values from DSC_SLICE_CAP_1 and DSC_SLICE_CAP2 */
- u8 slice_cap2 = dsc_dpcd[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT];
-
- if (slice_cap2 & DP_DSC_24_PER_DP_DSC_SINK)
- return 24;
- if (slice_cap2 & DP_DSC_20_PER_DP_DSC_SINK)
- return 20;
- if (slice_cap2 & DP_DSC_16_PER_DP_DSC_SINK)
- return 16;
- if (slice_cap1 & DP_DSC_12_PER_DP_DSC_SINK)
- return 12;
- if (slice_cap1 & DP_DSC_10_PER_DP_DSC_SINK)
- return 10;
- if (slice_cap1 & DP_DSC_8_PER_DP_DSC_SINK)
- return 8;
- if (slice_cap1 & DP_DSC_6_PER_DP_DSC_SINK)
- return 6;
- if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK)
- return 4;
- if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK)
- return 2;
- if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK)
- return 1;
- }
-
- return 0;
+ return fls(drm_dp_dsc_sink_slice_count_mask(dsc_dpcd, is_edp));
}
EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count);
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 64e5c176d5cc..be749dcad3b5 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -4572,7 +4572,8 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state,
if (!payload->delete) {
payload->pbn = 0;
payload->delete = true;
- topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
+ if (payload->vcpi > 0)
+ topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
}
return 0;
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 67e095e398a3..6d3ea8056b60 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -906,6 +906,7 @@ drm_atomic_private_obj_init(struct drm_device *dev,
drm_modeset_lock_init(&obj->lock);
+ obj->dev = dev;
obj->state = state;
obj->funcs = funcs;
list_add_tail(&obj->head, &dev->mode_config.privobj_list);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 8f355df883d8..db40c26d1cb3 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -27,6 +27,7 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/srcu.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
@@ -202,6 +203,67 @@ static DEFINE_MUTEX(bridge_lock);
static LIST_HEAD(bridge_list);
static LIST_HEAD(bridge_lingering_list);
+DEFINE_STATIC_SRCU(drm_bridge_unplug_srcu);
+
+/**
+ * drm_bridge_enter - Enter DRM bridge critical section
+ * @bridge: DRM bridge
+ * @idx: Pointer to index that will be passed to the matching drm_bridge_exit()
+ *
+ * This function marks and protects the beginning of a section that should not
+ * be entered after the bridge has been unplugged. The section end is marked
+ * with drm_bridge_exit(). Calls to this function can be nested.
+ *
+ * Returns:
+ * True if it is OK to enter the section, false otherwise.
+ */
+bool drm_bridge_enter(struct drm_bridge *bridge, int *idx)
+{
+ *idx = srcu_read_lock(&drm_bridge_unplug_srcu);
+
+ if (bridge->unplugged) {
+ srcu_read_unlock(&drm_bridge_unplug_srcu, *idx);
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(drm_bridge_enter);
+
+/**
+ * drm_bridge_exit - Exit DRM bridge critical section
+ * @idx: index returned by drm_bridge_enter()
+ *
+ * This function marks the end of a section that should not be entered after
+ * the bridge has been unplugged.
+ */
+void drm_bridge_exit(int idx)
+{
+ srcu_read_unlock(&drm_bridge_unplug_srcu, idx);
+}
+EXPORT_SYMBOL(drm_bridge_exit);
+
+/**
+ * drm_bridge_unplug - declare a DRM bridge was unplugged and remove it
+ * @bridge: DRM bridge
+ *
+ * This tells the bridge has been physically unplugged and no operations on
+ * device resources must be done anymore. Entry-points can use
+ * drm_bridge_enter() and drm_bridge_exit() to protect device resources in
+ * a race free manner.
+ *
+ * Also unregisters the bridge.
+ */
+void drm_bridge_unplug(struct drm_bridge *bridge)
+{
+ bridge->unplugged = true;
+
+ synchronize_srcu(&drm_bridge_unplug_srcu);
+
+ drm_bridge_remove(bridge);
+}
+EXPORT_SYMBOL(drm_bridge_unplug);
+
static void __drm_bridge_free(struct kref *kref)
{
struct drm_bridge *bridge = container_of(kref, struct drm_bridge, refcount);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 4a7f72044ab8..29c3c7bb7d67 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -75,9 +75,6 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem,
"Allow unsafe leaking fbdev physical smem address [default=false]");
#endif
-static LIST_HEAD(kernel_fb_helper_list);
-static DEFINE_MUTEX(kernel_fb_helper_lock);
-
/**
* DOC: fbdev helpers
*
@@ -115,101 +112,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* mmap page writes.
*/
-static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
-{
- uint16_t *r_base, *g_base, *b_base;
-
- if (crtc->funcs->gamma_set == NULL)
- return;
-
- r_base = crtc->gamma_store;
- g_base = r_base + crtc->gamma_size;
- b_base = g_base + crtc->gamma_size;
-
- crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
- crtc->gamma_size, NULL);
-}
-
-/**
- * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter
- * @info: fbdev registered by the helper
- */
-int drm_fb_helper_debug_enter(struct fb_info *info)
-{
- struct drm_fb_helper *helper = info->par;
- const struct drm_crtc_helper_funcs *funcs;
- struct drm_mode_set *mode_set;
-
- list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
- mutex_lock(&helper->client.modeset_mutex);
- drm_client_for_each_modeset(mode_set, &helper->client) {
- if (!mode_set->crtc->enabled)
- continue;
-
- funcs = mode_set->crtc->helper_private;
- if (funcs->mode_set_base_atomic == NULL)
- continue;
-
- if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
- continue;
-
- funcs->mode_set_base_atomic(mode_set->crtc,
- mode_set->fb,
- mode_set->x,
- mode_set->y,
- ENTER_ATOMIC_MODE_SET);
- }
- mutex_unlock(&helper->client.modeset_mutex);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(drm_fb_helper_debug_enter);
-
-/**
- * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave
- * @info: fbdev registered by the helper
- */
-int drm_fb_helper_debug_leave(struct fb_info *info)
-{
- struct drm_fb_helper *helper = info->par;
- struct drm_client_dev *client = &helper->client;
- struct drm_device *dev = helper->dev;
- struct drm_crtc *crtc;
- const struct drm_crtc_helper_funcs *funcs;
- struct drm_mode_set *mode_set;
- struct drm_framebuffer *fb;
-
- mutex_lock(&client->modeset_mutex);
- drm_client_for_each_modeset(mode_set, client) {
- crtc = mode_set->crtc;
- if (drm_drv_uses_atomic_modeset(crtc->dev))
- continue;
-
- funcs = crtc->helper_private;
- fb = crtc->primary->fb;
-
- if (!crtc->enabled)
- continue;
-
- if (!fb) {
- drm_err(dev, "no fb to restore?\n");
- continue;
- }
-
- if (funcs->mode_set_base_atomic == NULL)
- continue;
-
- drm_fb_helper_restore_lut_atomic(mode_set->crtc);
- funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
- crtc->y, LEAVE_ATOMIC_MODE_SET);
- }
- mutex_unlock(&client->modeset_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_fb_helper_debug_leave);
-
static int
__drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper,
bool force)
@@ -397,7 +299,6 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
if (!preferred_bpp)
preferred_bpp = 32;
- INIT_LIST_HEAD(&helper->kernel_fb_list);
spin_lock_init(&helper->damage_lock);
INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work);
@@ -534,11 +435,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
drm_fb_helper_release_info(fb_helper);
- mutex_lock(&kernel_fb_helper_lock);
- if (!list_empty(&fb_helper->kernel_fb_list))
- list_del(&fb_helper->kernel_fb_list);
- mutex_unlock(&kernel_fb_helper_lock);
-
if (!fb_helper->client.funcs)
drm_client_release(&fb_helper->client);
}
@@ -1766,10 +1662,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
drm_info(dev, "fb%d: %s frame buffer device\n",
info->node, info->fix.id);
- mutex_lock(&kernel_fb_helper_lock);
- list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
- mutex_unlock(&kernel_fb_helper_lock);
-
return 0;
err_drm_fb_helper_release_info:
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index efc79bbf3c73..127fbebcf175 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -29,6 +29,9 @@
#include <linux/export.h>
#include <linux/file.h>
#include <linux/fs.h>
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#include <linux/fs_context.h>
+#endif
#include <linux/iosys-map.h>
#include <linux/mem_encrypt.h>
#include <linux/mm.h>
@@ -36,6 +39,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
+#include <linux/sched/mm.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
@@ -81,6 +85,60 @@
* up at a later date, and as our interface with shmfs for memory allocation.
*/
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static void drm_gem_huge_mnt_free(struct drm_device *dev, void *data)
+{
+ kern_unmount(dev->huge_mnt);
+}
+
+/**
+ * drm_gem_huge_mnt_create - Create, mount and use a huge tmpfs mountpoint
+ * @dev: DRM device that will use the huge tmpfs mountpoint
+ * @value: huge tmpfs mount option value
+ *
+ * This function creates and mounts a dedicated huge tmpfs mountpoint for the
+ * lifetime of the DRM device @dev which is used at GEM object initialization
+ * with drm_gem_object_init().
+ *
+ * The most common option for @value is "within_size" which only allocates huge
+ * pages if the page will be fully within the GEM object size. "always",
+ * "advise" and "never" are supported too but the latter would just create a
+ * mountpoint similar to the default one (`shm_mnt`). See shmemfs and
+ * Transparent Hugepage for more information.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value)
+{
+ struct file_system_type *type;
+ struct fs_context *fc;
+ int ret;
+
+ if (unlikely(drm_gem_get_huge_mnt(dev)))
+ return 0;
+
+ type = get_fs_type("tmpfs");
+ if (unlikely(!type))
+ return -EOPNOTSUPP;
+ fc = fs_context_for_mount(type, SB_KERNMOUNT);
+ if (IS_ERR(fc))
+ return PTR_ERR(fc);
+ ret = vfs_parse_fs_string(fc, "source", "tmpfs");
+ if (unlikely(ret))
+ return -ENOPARAM;
+ ret = vfs_parse_fs_string(fc, "huge", value);
+ if (unlikely(ret))
+ return -ENOPARAM;
+
+ dev->huge_mnt = fc_mount_longterm(fc);
+ put_fs_context(fc);
+
+ return drmm_add_action_or_reset(dev, drm_gem_huge_mnt_free, NULL);
+}
+EXPORT_SYMBOL_GPL(drm_gem_huge_mnt_create);
+#endif
+
static void
drm_gem_init_release(struct drm_device *dev, void *ptr)
{
@@ -113,29 +171,28 @@ drm_gem_init(struct drm_device *dev)
}
/**
- * drm_gem_object_init_with_mnt - initialize an allocated shmem-backed GEM
- * object in a given shmfs mountpoint
+ * drm_gem_object_init - initialize an allocated shmem-backed GEM object
*
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
- * @gemfs: tmpfs mount where the GEM object will be created. If NULL, use
- * the usual tmpfs mountpoint (`shm_mnt`).
*
* Initialize an already allocated GEM object of the specified size with
- * shmfs backing store.
+ * shmfs backing store. A huge mountpoint can be used by calling
+ * drm_gem_huge_mnt_create() beforehand.
*/
-int drm_gem_object_init_with_mnt(struct drm_device *dev,
- struct drm_gem_object *obj, size_t size,
- struct vfsmount *gemfs)
+int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
+ size_t size)
{
+ struct vfsmount *huge_mnt;
struct file *filp;
drm_gem_private_object_init(dev, obj, size);
- if (gemfs)
- filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
- VM_NORESERVE);
+ huge_mnt = drm_gem_get_huge_mnt(dev);
+ if (huge_mnt)
+ filp = shmem_file_setup_with_mnt(huge_mnt, "drm mm object",
+ size, VM_NORESERVE);
else
filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
@@ -146,22 +203,6 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
return 0;
}
-EXPORT_SYMBOL(drm_gem_object_init_with_mnt);
-
-/**
- * drm_gem_object_init - initialize an allocated shmem-backed GEM object
- * @dev: drm_device the object should be initialized for
- * @obj: drm_gem_object to initialize
- * @size: object size
- *
- * Initialize an already allocated GEM object of the specified size with
- * shmfs backing store.
- */
-int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
- size_t size)
-{
- return drm_gem_object_init_with_mnt(dev, obj, size, NULL);
-}
EXPORT_SYMBOL(drm_gem_object_init);
/**
@@ -969,8 +1010,10 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
if (!obj)
return -ENOENT;
- if (args->handle == args->new_handle)
- return 0;
+ if (args->handle == args->new_handle) {
+ ret = 0;
+ goto out;
+ }
mutex_lock(&file_priv->prime.lock);
@@ -1002,6 +1045,8 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
out_unlock:
mutex_unlock(&file_priv->prime.lock);
+out:
+ drm_gem_object_put(obj);
return ret;
}
@@ -1177,36 +1222,27 @@ err_drm_gem_object_put:
}
EXPORT_SYMBOL(drm_gem_mmap_obj);
-/**
- * drm_gem_mmap - memory map routine for GEM objects
- * @filp: DRM file pointer
- * @vma: VMA for the area to be mapped
- *
- * If a driver supports GEM object mapping, mmap calls on the DRM file
- * descriptor will end up here.
- *
- * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
- * contain the fake offset we created when the GTT map ioctl was called on
- * the object) and map it with a call to drm_gem_mmap_obj().
- *
- * If the caller is not granted access to the buffer object, the mmap will fail
- * with EACCES. Please see the vma manager for more information.
+/*
+ * Look up a GEM object in offset space based on the exact start address. The
+ * caller must be granted access to the object. Returns a GEM object on success
+ * or a negative error code on failure. The returned GEM object needs to be
+ * released with drm_gem_object_put().
*/
-int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+static struct drm_gem_object *
+drm_gem_object_lookup_at_offset(struct file *filp, unsigned long start,
+ unsigned long pages)
{
struct drm_file *priv = filp->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_gem_object *obj = NULL;
struct drm_vma_offset_node *node;
- int ret;
if (drm_dev_is_unplugged(dev))
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
drm_vma_offset_lock_lookup(dev->vma_offset_manager);
node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
- vma->vm_pgoff,
- vma_pages(vma));
+ start, pages);
if (likely(node)) {
obj = container_of(node, struct drm_gem_object, vma_node);
/*
@@ -1225,14 +1261,88 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
if (!obj)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (!drm_vma_node_is_allowed(node, priv)) {
drm_gem_object_put(obj);
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
- ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT,
+ return obj;
+}
+
+#ifdef CONFIG_MMU
+/**
+ * drm_gem_get_unmapped_area - get memory mapping region routine for GEM objects
+ * @filp: DRM file pointer
+ * @uaddr: User address hint
+ * @len: Mapping length
+ * @pgoff: Offset (in pages)
+ * @flags: Mapping flags
+ *
+ * If a driver supports GEM object mapping, before ending up in drm_gem_mmap(),
+ * mmap calls on the DRM file descriptor will first try to find a free linear
+ * address space large enough for a mapping. Since GEM objects are backed by
+ * shmem buffers, this should preferably be handled by the shmem virtual memory
+ * filesystem which can appropriately align addresses to huge page sizes when
+ * needed.
+ *
+ * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
+ * contain the fake offset we created) and call shmem_get_unmapped_area() with
+ * the right file pointer.
+ *
+ * If a GEM object is not available at the given offset or if the caller is not
+ * granted access to it, fall back to mm_get_unmapped_area().
+ */
+unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct drm_gem_object *obj;
+ unsigned long ret;
+
+ obj = drm_gem_object_lookup_at_offset(filp, pgoff, len >> PAGE_SHIFT);
+ if (IS_ERR(obj) || !obj->filp || !obj->filp->f_op->get_unmapped_area)
+ return mm_get_unmapped_area(filp, uaddr, len, 0,
+ flags);
+
+ ret = obj->filp->f_op->get_unmapped_area(obj->filp, uaddr, len, 0,
+ flags);
+
+ drm_gem_object_put(obj);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(drm_gem_get_unmapped_area);
+#endif
+
+/**
+ * drm_gem_mmap - memory map routine for GEM objects
+ * @filp: DRM file pointer
+ * @vma: VMA for the area to be mapped
+ *
+ * If a driver supports GEM object mapping, mmap calls on the DRM file
+ * descriptor will end up here.
+ *
+ * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
+ * contain the fake offset we created) and map it with a call to
+ * drm_gem_mmap_obj().
+ *
+ * If the caller is not granted access to the buffer object, the mmap will fail
+ * with EACCES. Please see the vma manager for more information.
+ */
+int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ obj = drm_gem_object_lookup_at_offset(filp, vma->vm_pgoff,
+ vma_pages(vma));
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ ret = drm_gem_mmap_obj(obj,
+ drm_vma_node_size(&obj->vma_node) << PAGE_SHIFT,
vma);
drm_gem_object_put(obj);
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 93b9cff89080..fbd1164174b0 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -50,7 +50,7 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
};
static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem,
- size_t size, bool private, struct vfsmount *gemfs)
+ size_t size, bool private)
{
struct drm_gem_object *obj = &shmem->base;
int ret = 0;
@@ -62,7 +62,7 @@ static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_obj
drm_gem_private_object_init(dev, obj, size);
shmem->map_wc = false; /* dma-buf mappings use always writecombine */
} else {
- ret = drm_gem_object_init_with_mnt(dev, obj, size, gemfs);
+ ret = drm_gem_object_init(dev, obj, size);
}
if (ret) {
drm_gem_private_object_fini(obj);
@@ -94,22 +94,24 @@ err_release:
}
/**
- * drm_gem_shmem_init - Initialize an allocated object.
+ * drm_gem_shmem_init - Initialize an allocated object of the given size
* @dev: DRM device
- * @obj: The allocated shmem GEM object.
+ * @shmem: shmem GEM object to initialize
+ * @size: Size of the object to initialize
+ *
+ * This function initializes an allocated shmem GEM object.
*
* Returns:
* 0 on success, or a negative error code on failure.
*/
int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size)
{
- return __drm_gem_shmem_init(dev, shmem, size, false, NULL);
+ return __drm_gem_shmem_init(dev, shmem, size, false);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_init);
static struct drm_gem_shmem_object *
-__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
- struct vfsmount *gemfs)
+__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
{
struct drm_gem_shmem_object *shmem;
struct drm_gem_object *obj;
@@ -129,7 +131,7 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
obj = &shmem->base;
}
- ret = __drm_gem_shmem_init(dev, shmem, size, private, gemfs);
+ ret = __drm_gem_shmem_init(dev, shmem, size, private);
if (ret) {
kfree(obj);
return ERR_PTR(ret);
@@ -150,32 +152,11 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
*/
struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)
{
- return __drm_gem_shmem_create(dev, size, false, NULL);
+ return __drm_gem_shmem_create(dev, size, false);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
/**
- * drm_gem_shmem_create_with_mnt - Allocate an object with the given size in a
- * given mountpoint
- * @dev: DRM device
- * @size: Size of the object to allocate
- * @gemfs: tmpfs mount where the GEM object will be created
- *
- * This function creates a shmem GEM object in a given tmpfs mountpoint.
- *
- * Returns:
- * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative
- * error code on failure.
- */
-struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev,
- size_t size,
- struct vfsmount *gemfs)
-{
- return __drm_gem_shmem_create(dev, size, false, gemfs);
-}
-EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt);
-
-/**
* drm_gem_shmem_release - Release resources associated with a shmem GEM object.
* @shmem: shmem GEM object
*
@@ -567,6 +548,26 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
+static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr,
+ struct page *page)
+{
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+ unsigned long pfn = page_to_pfn(page);
+ unsigned long paddr = pfn << PAGE_SHIFT;
+ bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK);
+
+ if (aligned &&
+ pmd_none(*vmf->pmd) &&
+ folio_test_pmd_mappable(page_folio(page))) {
+ pfn &= PMD_MASK >> PAGE_SHIFT;
+ if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE)
+ return true;
+ }
+#endif
+
+ return false;
+}
+
static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
@@ -574,11 +575,12 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
loff_t num_pages = obj->size >> PAGE_SHIFT;
vm_fault_t ret;
- struct page *page;
+ struct page **pages = shmem->pages;
pgoff_t page_offset;
+ unsigned long pfn;
- /* We don't use vmf->pgoff since that has the fake offset */
- page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ /* Offset to faulty address in the VMA. */
+ page_offset = vmf->pgoff - vma->vm_pgoff;
dma_resv_lock(shmem->base.resv, NULL);
@@ -586,12 +588,18 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||
shmem->madv < 0) {
ret = VM_FAULT_SIGBUS;
- } else {
- page = shmem->pages[page_offset];
+ goto out;
+ }
- ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
+ if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) {
+ ret = VM_FAULT_NOPAGE;
+ goto out;
}
+ pfn = page_to_pfn(pages[page_offset]);
+ ret = vmf_insert_pfn(vma, vmf->address, pfn);
+
+ out:
dma_resv_unlock(shmem->base.resv);
return ret;
@@ -824,7 +832,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
size_t size = PAGE_ALIGN(attach->dmabuf->size);
struct drm_gem_shmem_object *shmem;
- shmem = __drm_gem_shmem_create(dev, size, true, NULL);
+ shmem = __drm_gem_shmem_create(dev, size, true);
if (IS_ERR(shmem))
return ERR_CAST(shmem);
@@ -872,7 +880,7 @@ struct drm_gem_object *drm_gem_shmem_prime_import_no_map(struct drm_device *dev,
size = PAGE_ALIGN(attach->dmabuf->size);
- shmem = __drm_gem_shmem_create(dev, size, true, NULL);
+ shmem = __drm_gem_shmem_create(dev, size, true);
if (IS_ERR(shmem)) {
ret = PTR_ERR(shmem);
goto fail_detach;
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
index d4b6ea42db0f..f42be7f1d8c2 100644
--- a/drivers/gpu/drm/drm_panic.c
+++ b/drivers/gpu/drm/drm_panic.c
@@ -39,12 +39,6 @@ MODULE_AUTHOR("Jocelyn Falempe");
MODULE_DESCRIPTION("DRM panic handler");
MODULE_LICENSE("GPL");
-static char drm_panic_screen[16] = CONFIG_DRM_PANIC_SCREEN;
-module_param_string(panic_screen, drm_panic_screen, sizeof(drm_panic_screen), 0644);
-MODULE_PARM_DESC(panic_screen,
- "Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default="
- CONFIG_DRM_PANIC_SCREEN "]");
-
/**
* DOC: overview
*
@@ -813,14 +807,59 @@ static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
draw_panic_static_user(sb);
}
#else
-static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
+static void drm_panic_qr_init(void) {};
+static void drm_panic_qr_exit(void) {};
+#endif
+
+enum drm_panic_type {
+ DRM_PANIC_TYPE_KMSG,
+ DRM_PANIC_TYPE_USER,
+ DRM_PANIC_TYPE_QR,
+};
+
+static enum drm_panic_type drm_panic_type = -1;
+
+static const char *drm_panic_type_map[] = {
+ [DRM_PANIC_TYPE_KMSG] = "kmsg",
+ [DRM_PANIC_TYPE_USER] = "user",
+#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
+ [DRM_PANIC_TYPE_QR] = "qr",
+#endif
+};
+
+static int drm_panic_type_set(const char *val, const struct kernel_param *kp)
{
- draw_panic_static_user(sb);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(drm_panic_type_map); i++) {
+ if (!strcmp(val, drm_panic_type_map[i])) {
+ drm_panic_type = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
}
-static void drm_panic_qr_init(void) {};
-static void drm_panic_qr_exit(void) {};
+static int drm_panic_type_get(char *buffer, const struct kernel_param *kp)
+{
+ return scnprintf(buffer, PAGE_SIZE, "%s\n",
+ drm_panic_type_map[drm_panic_type]);
+}
+
+static const struct kernel_param_ops drm_panic_ops = {
+ .set = drm_panic_type_set,
+ .get = drm_panic_type_get,
+};
+
+module_param_cb(panic_screen, &drm_panic_ops, NULL, 0644);
+MODULE_PARM_DESC(panic_screen,
+#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
+ "Choose what will be displayed by drm_panic, 'user', 'kmsg' or 'qr' [default="
+#else
+ "Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default="
#endif
+ CONFIG_DRM_PANIC_SCREEN "]");
/*
* drm_panic_is_format_supported()
@@ -838,11 +877,19 @@ static bool drm_panic_is_format_supported(const struct drm_format_info *format)
static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
{
- if (!strcmp(drm_panic_screen, "kmsg")) {
+ switch (drm_panic_type) {
+ case DRM_PANIC_TYPE_KMSG:
draw_panic_static_kmsg(sb);
- } else if (!strcmp(drm_panic_screen, "qr_code")) {
+ break;
+
+#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
+ case DRM_PANIC_TYPE_QR:
draw_panic_static_qr_code(sb);
- } else {
+ break;
+#endif
+
+ case DRM_PANIC_TYPE_USER:
+ default:
draw_panic_static_user(sb);
}
}
@@ -1025,6 +1072,8 @@ void drm_panic_unregister(struct drm_device *dev)
*/
void __init drm_panic_init(void)
{
+ if (drm_panic_type == -1)
+ drm_panic_type_set(CONFIG_DRM_PANIC_SCREEN, NULL);
drm_panic_qr_init();
}
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index b143589717e6..bed2562bf911 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -1867,9 +1867,9 @@ int drm_plane_create_color_pipeline_property(struct drm_plane *plane,
prop = drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC,
"COLOR_PIPELINE",
all_pipelines, len);
- if (IS_ERR(prop)) {
+ if (!prop) {
kfree(all_pipelines);
- return PTR_ERR(prop);
+ return -ENOMEM;
}
drm_object_attach_property(&plane->base, prop, 0);
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index e1b0fa4000cd..2d4ab745fdad 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -250,14 +250,14 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
{
struct drm_syncobj *syncobj;
- spin_lock(&file_private->syncobj_table_lock);
+ xa_lock(&file_private->syncobj_xa);
/* Check if we currently have a reference on the object */
- syncobj = idr_find(&file_private->syncobj_idr, handle);
+ syncobj = xa_load(&file_private->syncobj_xa, handle);
if (syncobj)
drm_syncobj_get(syncobj);
- spin_unlock(&file_private->syncobj_table_lock);
+ xa_unlock(&file_private->syncobj_xa);
return syncobj;
}
@@ -598,23 +598,15 @@ int drm_syncobj_get_handle(struct drm_file *file_private,
{
int ret;
- /* take a reference to put in the idr */
+ /* take a reference to put in the xarray */
drm_syncobj_get(syncobj);
- idr_preload(GFP_KERNEL);
- spin_lock(&file_private->syncobj_table_lock);
- ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
- spin_unlock(&file_private->syncobj_table_lock);
-
- idr_preload_end();
-
- if (ret < 0) {
+ ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
+ GFP_NOWAIT);
+ if (ret)
drm_syncobj_put(syncobj);
- return ret;
- }
- *handle = ret;
- return 0;
+ return ret;
}
EXPORT_SYMBOL(drm_syncobj_get_handle);
@@ -638,10 +630,7 @@ static int drm_syncobj_destroy(struct drm_file *file_private,
{
struct drm_syncobj *syncobj;
- spin_lock(&file_private->syncobj_table_lock);
- syncobj = idr_remove(&file_private->syncobj_idr, handle);
- spin_unlock(&file_private->syncobj_table_lock);
-
+ syncobj = xa_erase(&file_private->syncobj_xa, handle);
if (!syncobj)
return -EINVAL;
@@ -722,20 +711,13 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
if (fd_file(f)->f_op != &drm_syncobj_file_fops)
return -EINVAL;
- /* take a reference to put in the idr */
+ /* take a reference to put in the xarray */
syncobj = fd_file(f)->private_data;
drm_syncobj_get(syncobj);
- idr_preload(GFP_KERNEL);
- spin_lock(&file_private->syncobj_table_lock);
- ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
- spin_unlock(&file_private->syncobj_table_lock);
- idr_preload_end();
-
- if (ret > 0) {
- *handle = ret;
- ret = 0;
- } else
+ ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
+ GFP_NOWAIT);
+ if (ret)
drm_syncobj_put(syncobj);
return ret;
@@ -814,17 +796,7 @@ err_put_fd:
void
drm_syncobj_open(struct drm_file *file_private)
{
- idr_init_base(&file_private->syncobj_idr, 1);
- spin_lock_init(&file_private->syncobj_table_lock);
-}
-
-static int
-drm_syncobj_release_handle(int id, void *ptr, void *data)
-{
- struct drm_syncobj *syncobj = ptr;
-
- drm_syncobj_put(syncobj);
- return 0;
+ xa_init_flags(&file_private->syncobj_xa, XA_FLAGS_ALLOC1);
}
/**
@@ -838,9 +810,12 @@ drm_syncobj_release_handle(int id, void *ptr, void *data)
void
drm_syncobj_release(struct drm_file *file_private)
{
- idr_for_each(&file_private->syncobj_idr,
- &drm_syncobj_release_handle, file_private);
- idr_destroy(&file_private->syncobj_idr);
+ struct drm_syncobj *syncobj;
+ unsigned long handle;
+
+ xa_for_each(&file_private->syncobj_xa, handle, syncobj)
+ drm_syncobj_put(syncobj);
+ xa_destroy(&file_private->syncobj_xa);
}
int
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 5c14140cd0c2..42fe11cc139b 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -551,7 +551,7 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
dev->num_crtcs = num_crtcs;
for (i = 0; i < num_crtcs; i++) {
- struct drm_vblank_crtc *vblank = &dev->vblank[i];
+ struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, i);
vblank->dev = dev;
vblank->pipe = i;
@@ -605,7 +605,9 @@ EXPORT_SYMBOL(drm_dev_has_vblank);
*/
wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
{
- return &crtc->dev->vblank[drm_crtc_index(crtc)].queue;
+ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
+
+ return &vblank->queue;
}
EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
@@ -710,7 +712,6 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(
{
struct drm_device *dev = crtc->dev;
unsigned int pipe = crtc->index;
- struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
struct timespec64 ts_etime, ts_vblank_time;
ktime_t stime, etime;
bool vbl_status;
@@ -729,10 +730,13 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(
return false;
}
- if (drm_drv_uses_atomic_modeset(dev))
+ if (drm_drv_uses_atomic_modeset(dev)) {
+ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
+
mode = &vblank->hwmode;
- else
+ } else {
mode = &crtc->hwmode;
+ }
/* If mode timing undefined, just return as no-op:
* Happens during initial modesetting of a crtc.
@@ -1285,29 +1289,27 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
EXPORT_SYMBOL(drm_crtc_vblank_put);
/**
- * drm_wait_one_vblank - wait for one vblank
- * @dev: DRM device
- * @pipe: CRTC index
+ * drm_crtc_wait_one_vblank - wait for one vblank
+ * @crtc: DRM crtc
*
- * This waits for one vblank to pass on @pipe, using the irq driver interfaces.
- * It is a failure to call this when the vblank irq for @pipe is disabled, e.g.
+ * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
+ * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
* due to lack of driver support or because the crtc is off.
*
- * This is the legacy version of drm_crtc_wait_one_vblank().
+ * Returns: 0 on success, negative error on failures.
*/
-void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe)
+int drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
{
- struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe);
+ struct drm_device *dev = crtc->dev;
+ int pipe = drm_crtc_index(crtc);
+ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
int ret;
u64 last;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
- return;
-
ret = drm_vblank_get(dev, pipe);
if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n",
pipe, ret))
- return;
+ return ret;
last = drm_vblank_count(dev, pipe);
@@ -1318,20 +1320,8 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe)
drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe);
drm_vblank_put(dev, pipe);
-}
-EXPORT_SYMBOL(drm_wait_one_vblank);
-/**
- * drm_crtc_wait_one_vblank - wait for one vblank
- * @crtc: DRM crtc
- *
- * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
- * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
- * due to lack of driver support or because the crtc is off.
- */
-void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
-{
- drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
+ return ret ? 0 : -ETIMEDOUT;
}
EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
@@ -1794,7 +1784,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
if (pipe >= dev->num_crtcs)
return -EINVAL;
- vblank = &dev->vblank[pipe];
+ vblank = drm_vblank_crtc(dev, pipe);
/* If the counter is currently enabled and accurate, short-circuit
* queries to return the cached timestamp of the last vblank.
diff --git a/drivers/gpu/drm/hyperv/Kconfig b/drivers/gpu/drm/hyperv/Kconfig
new file mode 100644
index 000000000000..86234f6a73f2
--- /dev/null
+++ b/drivers/gpu/drm/hyperv/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_HYPERV
+ tristate "DRM Support for Hyper-V synthetic video device"
+ depends on DRM && PCI && HYPERV_VMBUS
+ select DRM_CLIENT_SELECTION
+ select DRM_KMS_HELPER
+ select DRM_GEM_SHMEM_HELPER
+ help
+ This is a KMS driver for Hyper-V synthetic video device. Choose this
+ option if you would like to enable drm driver for Hyper-V virtual
+ machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so
+ that DRM driver is used by default.
+
+ If M is selected the module will be called hyperv_drm.
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 4db24050edb0..5f7b2bbe448c 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -27,7 +27,10 @@ i915-y += \
i915_config.o \
i915_driver.o \
i915_drm_client.o \
+ i915_edram.o \
+ i915_freq.o \
i915_getparam.o \
+ i915_gmch.o \
i915_ioctl.o \
i915_irq.o \
i915_mitigations.o \
@@ -54,12 +57,6 @@ i915-y += \
vlv_iosf_sb.o \
vlv_suspend.o
-# core peripheral code
-i915-y += \
- soc/intel_dram.o \
- soc/intel_gmch.o \
- soc/intel_rom.o
-
# core library code
i915-y += \
i915_memcpy.o \
@@ -77,6 +74,12 @@ i915-$(CONFIG_DEBUG_FS) += \
i915-$(CONFIG_PERF_EVENTS) += \
i915_pmu.o
+# core display adaptation
+i915-y += \
+ i915_display_pc8.o \
+ i915_hdcp_gsc.o \
+ i915_panic.o
+
# "Graphics Technology" (aka we talk to the gpu)
gt-y += \
gt/gen2_engine_cs.o \
@@ -170,8 +173,7 @@ gem-y += \
gem/i915_gem_ttm_move.o \
gem/i915_gem_ttm_pm.o \
gem/i915_gem_userptr.o \
- gem/i915_gem_wait.o \
- gem/i915_gemfs.o
+ gem/i915_gem_wait.o
i915-y += \
$(gem-y) \
i915_active.o \
@@ -268,6 +270,7 @@ i915-y += \
display/intel_dpll_mgr.o \
display/intel_dpt.o \
display/intel_dpt_common.o \
+ display/intel_dram.o \
display/intel_drrs.o \
display/intel_dsb.o \
display/intel_dsb_buffer.o \
@@ -281,7 +284,6 @@ i915-y += \
display/intel_frontbuffer.o \
display/intel_global_state.o \
display/intel_hdcp.o \
- display/intel_hdcp_gsc.o \
display/intel_hdcp_gsc_message.o \
display/intel_hotplug.o \
display/intel_hotplug_irq.o \
@@ -293,7 +295,7 @@ i915-y += \
display/intel_modeset_setup.o \
display/intel_modeset_verify.o \
display/intel_overlay.o \
- display/intel_panic.o \
+ display/intel_parent.o \
display/intel_pch.o \
display/intel_pch_display.o \
display/intel_pch_refclk.o \
@@ -302,6 +304,7 @@ i915-y += \
display/intel_pmdemand.o \
display/intel_psr.o \
display/intel_quirks.o \
+ display/intel_rom.o \
display/intel_sbi.o \
display/intel_sprite.o \
display/intel_sprite_uapi.o \
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index a3ff21b2f69f..4cb753177fd8 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -302,7 +302,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
wakeref = intel_display_power_get_if_enabled(display,
@@ -684,12 +684,11 @@ static void intel_enable_dp(struct intel_atomic_state *state,
struct intel_display *display = to_intel_display(state);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 dp_reg = intel_de_read(display, intel_dp->output_reg);
- intel_wakeref_t wakeref;
if (drm_WARN_ON(display->drm, dp_reg & DP_PORT_EN))
return;
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
if (display->platform.valleyview || display->platform.cherryview)
vlv_pps_port_enable_unlocked(encoder, pipe_config);
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index f6e2d1ed5639..8b22447e8e23 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -68,7 +68,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
wakeref = intel_display_power_get_if_enabled(display,
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c
index 51ccc6bd5f21..b1fecf178906 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.c
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c
@@ -22,7 +22,6 @@
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
-#include "intel_panic.h"
#include "intel_plane.h"
#include "intel_sprite.h"
@@ -134,7 +133,7 @@ static struct intel_fbc *i9xx_plane_fbc(struct intel_display *display,
enum i9xx_plane_id i9xx_plane)
{
if (i9xx_plane_has_fbc(display, i9xx_plane))
- return display->fbc[INTEL_FBC_A];
+ return display->fbc.instances[INTEL_FBC_A];
else
return NULL;
}
@@ -724,7 +723,7 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
u32 val;
@@ -819,7 +818,7 @@ unsigned int vlv_plane_min_alignment(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
- if (intel_plane_can_async_flip(plane, fb->format->format, fb->modifier))
+ if (intel_plane_can_async_flip(plane, fb->format, fb->modifier))
return 256 * 1024;
/* FIXME undocumented so not sure what's actually needed */
@@ -843,7 +842,7 @@ static unsigned int g4x_primary_min_alignment(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
- if (intel_plane_can_async_flip(plane, fb->format->format, fb->modifier))
+ if (intel_plane_can_async_flip(plane, fb->format, fb->modifier))
return 256 * 1024;
if (intel_scanout_needs_vtd_wa(display))
diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c
index 01f3803fa09f..167277cd8877 100644
--- a/drivers/gpu/drm/i915/display/i9xx_wm.c
+++ b/drivers/gpu/drm/i915/display/i9xx_wm.c
@@ -7,8 +7,6 @@
#include <drm/drm_print.h>
-#include "soc/intel_dram.h"
-
#include "i915_drv.h"
#include "i915_reg.h"
#include "i9xx_wm.h"
@@ -19,6 +17,7 @@
#include "intel_display.h"
#include "intel_display_regs.h"
#include "intel_display_trace.h"
+#include "intel_dram.h"
#include "intel_fb.h"
#include "intel_mchbar_regs.h"
#include "intel_wm.h"
@@ -91,7 +90,7 @@ static const struct cxsr_latency cxsr_latency_table[] = {
static const struct cxsr_latency *pnv_get_cxsr_latency(struct intel_display *display)
{
- const struct dram_info *dram_info = intel_dram_info(display->drm);
+ const struct dram_info *dram_info = intel_dram_info(display);
bool is_ddr3 = dram_info->type == INTEL_DRAM_DDR3;
int i;
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 9230792960f2..dac781f54661 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1411,7 +1411,7 @@ static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
enum port port;
for_each_dsi_port(port, intel_dsi->ports) {
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
intel_display_power_put(display,
@@ -1722,7 +1722,7 @@ static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
struct intel_display *display = to_intel_display(encoder);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
enum transcoder dsi_trans;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum port port;
bool ret = false;
u32 tmp;
diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c
index 6372f533f65b..7ce8c674bb03 100644
--- a/drivers/gpu/drm/i915/display/intel_alpm.c
+++ b/drivers/gpu/drm/i915/display/intel_alpm.c
@@ -326,11 +326,9 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp,
if (intel_dp->as_sdp_supported) {
u32 pr_alpm_ctl = PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T1;
- if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
- DP_PANEL_REPLAY_LINK_OFF_SUPPORTED_IN_PR_AFTER_ADAPTIVE_SYNC_SDP)
+ if (crtc_state->link_off_after_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_ALLOW_LINK_OFF_BETWEEN_AS_SDP_AND_SU;
- if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
- DP_PANEL_REPLAY_ASYNC_VIDEO_TIMING_NOT_SUPPORTED_IN_PR))
+ if (crtc_state->disable_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE;
intel_de_write(display, PR_ALPM_CTL(display, cpu_transcoder),
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index 5bdaef38f13d..5f3c175afdd2 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -1042,10 +1042,10 @@ int intel_audio_min_cdclk(const struct intel_crtc_state *crtc_state)
static unsigned long intel_audio_component_get_power(struct device *kdev)
{
struct intel_display *display = to_intel_display(kdev);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
/* Catch potential impedance mismatches before they occur! */
- BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long));
+ BUILD_BUG_ON(sizeof(wakeref) > sizeof(unsigned long));
wakeref = intel_display_power_get(display, POWER_DOMAIN_AUDIO_PLAYBACK);
@@ -1074,7 +1074,7 @@ static void intel_audio_component_put_power(struct device *kdev,
unsigned long cookie)
{
struct intel_display *display = to_intel_display(kdev);
- intel_wakeref_t wakeref = (intel_wakeref_t)cookie;
+ struct ref_tracker *wakeref = (struct ref_tracker *)cookie;
/* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */
if (--display->audio.power_refcount == 0)
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 4b41068e9e35..ae0b922d5bc3 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -34,14 +34,13 @@
#include <drm/drm_fixed.h>
#include <drm/drm_print.h>
-#include "soc/intel_rom.h"
-
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_rpm.h"
#include "intel_display_types.h"
#include "intel_display_utils.h"
#include "intel_gmbus.h"
+#include "intel_rom.h"
#define _INTEL_BIOS_PRIVATE
#include "intel_vbt_defs.h"
@@ -2529,6 +2528,54 @@ intel_bios_encoder_reject_edp_rate(const struct intel_bios_encoder_data *devdata
return devdata->child.edp_data_rate_override & edp_rate_override_mask(rate);
}
+static void sanitize_dedicated_external(struct intel_bios_encoder_data *devdata,
+ enum port port)
+{
+ struct intel_display *display = devdata->display;
+
+ if (!intel_bios_encoder_is_dedicated_external(devdata))
+ return;
+
+ /*
+ * Since dedicated_external is for ports connected to PHYs outside of
+ * the Type-C subsystem, clear bits that would only make sense for ports
+ * with PHYs in the Type-C subsystem.
+ */
+
+ /*
+ * Bit dp_usb_type_c is marked as "don't care" in Bspec when
+ * dedicated_external is set.
+ */
+ if (devdata->child.dp_usb_type_c) {
+ drm_dbg_kms(display->drm,
+ "VBT claims Port %c supports USB Type-C, but the port is dedicated external, ignoring\n",
+ port_name(port));
+ devdata->child.dp_usb_type_c = 0;
+ }
+
+ /*
+ * Bit tbt is marked as "don't care" in Bspec when dedicated_external is
+ * set.
+ */
+ if (devdata->child.tbt) {
+ drm_dbg_kms(display->drm,
+ "VBT claims Port %c supports TBT, but the port is dedicated external, ignoring\n",
+ port_name(port));
+ devdata->child.tbt = 0;
+ }
+
+ /*
+ * DDI allocation for TC capable ports only make sense for PHYs in the
+ * Type-C subsystem.
+ */
+ if (devdata->child.dyn_port_over_tc) {
+ drm_dbg_kms(display->drm,
+ "VBT claims Port %c supports dynamic DDI allocation in TCSS, but the port is dedicated external, ignoring\n",
+ port_name(port));
+ devdata->child.dyn_port_over_tc = 0;
+ }
+}
+
static void sanitize_device_type(struct intel_bios_encoder_data *devdata,
enum port port)
{
@@ -2693,6 +2740,16 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
supports_typec_usb, supports_tbt,
devdata->dsc != NULL);
+ if (intel_bios_encoder_is_dedicated_external(devdata))
+ drm_dbg_kms(display->drm,
+ "Port %c is dedicated external\n",
+ port_name(port));
+
+ if (intel_bios_encoder_supports_dyn_port_over_tc(devdata))
+ drm_dbg_kms(display->drm,
+ "Port %c supports dynamic DDI allocation in TCSS\n",
+ port_name(port));
+
hdmi_level_shift = intel_bios_hdmi_level_shift(devdata);
if (hdmi_level_shift >= 0) {
drm_dbg_kms(display->drm,
@@ -2750,6 +2807,7 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
return;
}
+ sanitize_dedicated_external(devdata, port);
sanitize_device_type(devdata, port);
sanitize_hdmi_level_shift(devdata, port);
}
@@ -2777,7 +2835,7 @@ static int child_device_expected_size(u16 version)
{
BUILD_BUG_ON(sizeof(struct child_device_config) < 40);
- if (version > 263)
+ if (version > 264)
return -ENOENT;
else if (version >= 263)
return 44;
@@ -3721,6 +3779,18 @@ bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devda
return devdata->display->vbt.version >= 209 && devdata->child.tbt;
}
+bool intel_bios_encoder_is_dedicated_external(const struct intel_bios_encoder_data *devdata)
+{
+ return devdata->display->vbt.version >= 264 &&
+ devdata->child.dedicated_external;
+}
+
+bool intel_bios_encoder_supports_dyn_port_over_tc(const struct intel_bios_encoder_data *devdata)
+{
+ return devdata->display->vbt.version >= 264 &&
+ devdata->child.dyn_port_over_tc;
+}
+
bool intel_bios_encoder_lane_reversal(const struct intel_bios_encoder_data *devdata)
{
return devdata && devdata->child.lane_reversal;
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index f9e438b2787b..75dff27b4228 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -79,6 +79,8 @@ bool intel_bios_encoder_supports_dp(const struct intel_bios_encoder_data *devdat
bool intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devdata);
+bool intel_bios_encoder_is_dedicated_external(const struct intel_bios_encoder_data *devdata);
+bool intel_bios_encoder_supports_dyn_port_over_tc(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_dp_dual_mode(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_is_lspcon(const struct intel_bios_encoder_data *devdata);
diff --git a/drivers/gpu/drm/i915/display/intel_bo.c b/drivers/gpu/drm/i915/display/intel_bo.c
index f3687eb63467..8f372b33d48b 100644
--- a/drivers/gpu/drm/i915/display/intel_bo.c
+++ b/drivers/gpu/drm/i915/display/intel_bo.c
@@ -6,6 +6,7 @@
#include "gem/i915_gem_mman.h"
#include "gem/i915_gem_object.h"
#include "gem/i915_gem_object_frontbuffer.h"
+#include "pxp/intel_pxp.h"
#include "i915_debugfs.h"
#include "intel_bo.h"
@@ -29,6 +30,11 @@ bool intel_bo_is_protected(struct drm_gem_object *obj)
return i915_gem_object_is_protected(to_intel_bo(obj));
}
+int intel_bo_key_check(struct drm_gem_object *obj)
+{
+ return intel_pxp_key_check(obj, false);
+}
+
int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
return i915_gem_fb_mmap(to_intel_bo(obj), vma);
diff --git a/drivers/gpu/drm/i915/display/intel_bo.h b/drivers/gpu/drm/i915/display/intel_bo.h
index fc05f680dc76..516a3836a6bc 100644
--- a/drivers/gpu/drm/i915/display/intel_bo.h
+++ b/drivers/gpu/drm/i915/display/intel_bo.h
@@ -16,6 +16,7 @@ bool intel_bo_is_tiled(struct drm_gem_object *obj);
bool intel_bo_is_userptr(struct drm_gem_object *obj);
bool intel_bo_is_shmem(struct drm_gem_object *obj);
bool intel_bo_is_protected(struct drm_gem_object *obj);
+int intel_bo_key_check(struct drm_gem_object *obj);
int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
int intel_bo_read_from_page(struct drm_gem_object *obj, u64 offset, void *dst, int size);
diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c
index 1f6461be50ef..d27835ed49c2 100644
--- a/drivers/gpu/drm/i915/display/intel_bw.c
+++ b/drivers/gpu/drm/i915/display/intel_bw.c
@@ -6,8 +6,6 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_print.h>
-#include "soc/intel_dram.h"
-
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_bw.h"
@@ -16,6 +14,7 @@
#include "intel_display_regs.h"
#include "intel_display_types.h"
#include "intel_display_utils.h"
+#include "intel_dram.h"
#include "intel_mchbar_regs.h"
#include "intel_pcode.h"
#include "intel_uncore.h"
@@ -800,7 +799,7 @@ static unsigned int icl_qgv_bw(struct intel_display *display,
void intel_bw_init_hw(struct intel_display *display)
{
- const struct dram_info *dram_info = intel_dram_info(display->drm);
+ const struct dram_info *dram_info = intel_dram_info(display);
if (!HAS_DISPLAY(display))
return;
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 37801c744b05..0aa59d624095 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -28,10 +28,7 @@
#include <drm/drm_fixed.h>
#include <drm/drm_print.h>
-#include "soc/intel_dram.h"
-
#include "hsw_ips.h"
-#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_audio.h"
@@ -42,11 +39,13 @@
#include "intel_display_regs.h"
#include "intel_display_types.h"
#include "intel_display_utils.h"
+#include "intel_dram.h"
#include "intel_mchbar_regs.h"
#include "intel_pci_config.h"
#include "intel_pcode.h"
#include "intel_plane.h"
#include "intel_psr.h"
+#include "intel_step.h"
#include "intel_vdsc.h"
#include "skl_watermark.h"
#include "skl_watermark_regs.h"
@@ -668,7 +667,7 @@ static void vlv_set_cdclk(struct intel_display *display,
{
int cdclk = cdclk_config->cdclk;
u32 val, cmd = cdclk_config->voltage_level;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int ret;
switch (cdclk) {
@@ -758,7 +757,7 @@ static void chv_set_cdclk(struct intel_display *display,
{
int cdclk = cdclk_config->cdclk;
u32 val, cmd = cdclk_config->voltage_level;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int ret;
switch (cdclk) {
@@ -3738,10 +3737,8 @@ static int pch_rawclk(struct intel_display *display)
static int i9xx_hrawclk(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
-
/* hrawclock is 1/4 the FSB frequency */
- return DIV_ROUND_CLOSEST(intel_fsb_freq(i915), 4);
+ return DIV_ROUND_CLOSEST(intel_fsb_freq(display), 4);
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c b/drivers/gpu/drm/i915/display/intel_cmtg.c
index 165138b95cb2..e1fdc6fe9762 100644
--- a/drivers/gpu/drm/i915/display/intel_cmtg.c
+++ b/drivers/gpu/drm/i915/display/intel_cmtg.c
@@ -85,7 +85,6 @@ static bool intel_cmtg_transcoder_is_secondary(struct intel_display *display,
enum transcoder trans)
{
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
u32 val = 0;
if (!HAS_TRANSCODER(display, trans))
@@ -93,7 +92,7 @@ static bool intel_cmtg_transcoder_is_secondary(struct intel_display *display,
power_domain = POWER_DOMAIN_TRANSCODER(trans);
- with_intel_display_power_if_enabled(display, power_domain, wakeref)
+ with_intel_display_power_if_enabled(display, power_domain)
val = intel_de_read(display, TRANS_DDI_FUNC_CTL2(display, trans));
return val & CMTG_SECONDARY_MODE;
diff --git a/drivers/gpu/drm/i915/display/intel_colorop.c b/drivers/gpu/drm/i915/display/intel_colorop.c
index f2fc0d8780ce..1d84933f05aa 100644
--- a/drivers/gpu/drm/i915/display/intel_colorop.c
+++ b/drivers/gpu/drm/i915/display/intel_colorop.c
@@ -2,7 +2,9 @@
/*
* Copyright © 2025 Intel Corporation
*/
+
#include "intel_colorop.h"
+#include "intel_display_types.h"
struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop)
{
diff --git a/drivers/gpu/drm/i915/display/intel_colorop.h b/drivers/gpu/drm/i915/display/intel_colorop.h
index 21d58eb9f3d0..9276eee6e75a 100644
--- a/drivers/gpu/drm/i915/display/intel_colorop.h
+++ b/drivers/gpu/drm/i915/display/intel_colorop.h
@@ -6,7 +6,9 @@
#ifndef __INTEL_COLOROP_H__
#define __INTEL_COLOROP_H__
-#include "intel_display_types.h"
+enum intel_color_block;
+struct drm_colorop;
+struct intel_colorop;
struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop);
struct intel_colorop *intel_colorop_alloc(void);
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 913d90a7a508..c128bc4215c4 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -156,27 +156,17 @@ void intel_connector_destroy(struct drm_connector *connector)
int intel_connector_register(struct drm_connector *_connector)
{
struct intel_connector *connector = to_intel_connector(_connector);
- struct drm_i915_private *i915 = to_i915(_connector->dev);
int ret;
ret = intel_panel_register(connector);
if (ret)
- goto err;
-
- if (i915_inject_probe_failure(i915)) {
- ret = -EFAULT;
- goto err_panel;
- }
+ return ret;
intel_connector_debugfs_add(connector);
return 0;
-
-err_panel:
- intel_panel_unregister(connector);
-err:
- return ret;
}
+ALLOW_ERROR_INJECTION(intel_connector_register, ERRNO);
void intel_connector_unregister(struct drm_connector *_connector)
{
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 82e89cdbe5a5..5f9a03877ea9 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -109,7 +109,7 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
struct intel_crt *crt = intel_encoder_to_crt(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
wakeref = intel_display_power_get_if_enabled(display,
@@ -847,7 +847,7 @@ intel_crt_detect(struct drm_connector *connector,
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
struct intel_encoder *encoder = &crt->base;
struct drm_atomic_state *state;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int status;
drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] force=%d\n",
@@ -936,7 +936,7 @@ static int intel_crt_get_modes(struct drm_connector *connector)
struct intel_display *display = to_intel_display(connector->dev);
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
struct intel_encoder *encoder = &crt->base;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
struct i2c_adapter *ddc;
int ret;
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 9d2a23c96c61..778ebc5095c3 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -13,8 +13,6 @@
#include <drm/drm_vblank.h>
#include <drm/drm_vblank_work.h>
-#include "i915_drv.h"
-#include "i915_vgpu.h"
#include "i9xx_plane.h"
#include "icl_dsi.h"
#include "intel_atomic.h"
@@ -28,6 +26,7 @@
#include "intel_drrs.h"
#include "intel_dsi.h"
#include "intel_fifo_underrun.h"
+#include "intel_parent.h"
#include "intel_pipe_crc.h"
#include "intel_plane.h"
#include "intel_psr.h"
@@ -309,7 +308,7 @@ static const struct drm_crtc_funcs i8xx_crtc_funcs = {
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
};
-int intel_crtc_init(struct intel_display *display, enum pipe pipe)
+static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
{
struct intel_plane *primary, *cursor;
const struct drm_crtc_funcs *funcs;
@@ -396,7 +395,7 @@ int intel_crtc_init(struct intel_display *display, enum pipe pipe)
drm_WARN_ON(display->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
- if (HAS_CASF(display))
+ if (HAS_CASF(display) && crtc->num_scalers >= 2)
drm_crtc_create_sharpness_strength_property(&crtc->base);
return 0;
@@ -407,6 +406,23 @@ fail:
return ret;
}
+int intel_crtc_init(struct intel_display *display)
+{
+ enum pipe pipe;
+ int ret;
+
+ drm_dbg_kms(display->drm, "%d display pipe%s available.\n",
+ INTEL_NUM_PIPES(display), str_plural(INTEL_NUM_PIPES(display)));
+
+ for_each_pipe(display, pipe) {
+ ret = __intel_crtc_init(display, pipe);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
int intel_crtc_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@@ -553,7 +569,7 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
new_plane_state, i) {
- if (old_plane_state->uapi.crtc == &crtc->base)
+ if (old_plane_state->hw.crtc == &crtc->base)
intel_plane_init_cursor_vblank_work(old_plane_state,
new_plane_state);
}
@@ -671,7 +687,6 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
int scanline_end = intel_get_crtc_scanline(crtc);
u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
ktime_t end_vbl_time = ktime_get();
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
drm_WARN_ON(display->drm, new_crtc_state->use_dsb);
@@ -706,7 +721,7 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
int i;
for_each_old_intel_plane_in_state(state, plane, old_plane_state, i) {
- if (old_plane_state->uapi.crtc == &crtc->base &&
+ if (old_plane_state->hw.crtc == &crtc->base &&
old_plane_state->unpin_work.vblank) {
drm_vblank_work_schedule(&old_plane_state->unpin_work,
drm_crtc_accurate_vblank_count(&crtc->base) + 1,
@@ -737,7 +752,7 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
local_irq_enable();
- if (intel_vgpu_active(dev_priv))
+ if (intel_parent_vgpu_active(display))
goto out;
if (crtc->debug.start_vbl_count &&
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h
index 07917e8a9ae3..12507b51ee77 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.h
+++ b/drivers/gpu/drm/i915/display/intel_crtc.h
@@ -37,7 +37,7 @@ void intel_crtc_arm_vblank_event(struct intel_crtc_state *crtc_state);
void intel_crtc_prepare_vblank_event(struct intel_crtc_state *crtc_state,
struct drm_pending_vblank_event **event);
u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state);
-int intel_crtc_init(struct intel_display *display, enum pipe pipe);
+int intel_crtc_init(struct intel_display *display);
int intel_crtc_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index a10b2425b94d..2c5d917fbd7e 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -324,7 +324,7 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(PIPE_A);
@@ -727,7 +727,7 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
u32 val;
@@ -974,6 +974,7 @@ static const struct drm_plane_funcs intel_cursor_plane_funcs = {
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = intel_cursor_format_mod_supported,
+ .format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static void intel_cursor_add_size_hints_property(struct intel_plane *plane)
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index d98b4cf6b60e..2c87c58812da 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -11,6 +11,7 @@
#include "intel_alpm.h"
#include "intel_cx0_phy.h"
#include "intel_cx0_phy_regs.h"
+#include "intel_display_regs.h"
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
@@ -104,11 +105,11 @@ static void intel_cx0_program_msgbus_timer(struct intel_encoder *encoder)
* We also do the msgbus timer programming here to ensure that the timer
* is already programmed before any access to the msgbus.
*/
-static intel_wakeref_t intel_cx0_phy_transaction_begin(struct intel_encoder *encoder)
+static struct ref_tracker *intel_cx0_phy_transaction_begin(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
intel_psr_pause(intel_dp);
wakeref = intel_display_power_get(display, POWER_DOMAIN_DC_OFF);
@@ -117,7 +118,7 @@ static intel_wakeref_t intel_cx0_phy_transaction_begin(struct intel_encoder *enc
return wakeref;
}
-static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref)
+static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, struct ref_tracker *wakeref)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -444,13 +445,38 @@ static u8 intel_c10_get_tx_term_ctl(const struct intel_crtc_state *crtc_state)
}
}
+static void intel_c10_msgbus_access_begin(struct intel_encoder *encoder,
+ u8 lane_mask)
+{
+ if (!intel_encoder_is_c10phy(encoder))
+ return;
+
+ intel_cx0_rmw(encoder, lane_mask, PHY_C10_VDR_CONTROL(1),
+ 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED);
+}
+
+static void intel_c10_msgbus_access_commit(struct intel_encoder *encoder,
+ u8 lane_mask, bool master_lane)
+{
+ u8 val = C10_VDR_CTRL_UPDATE_CFG;
+
+ if (!intel_encoder_is_c10phy(encoder))
+ return;
+
+ if (master_lane)
+ val |= C10_VDR_CTRL_MASTER_LANE;
+
+ intel_cx0_rmw(encoder, lane_mask, PHY_C10_VDR_CONTROL(1),
+ 0, val, MB_WRITE_COMMITTED);
+}
+
void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(encoder);
const struct intel_ddi_buf_trans *trans;
u8 owned_lane_mask;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int n_entries, ln;
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
@@ -467,9 +493,9 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
return;
}
+ intel_c10_msgbus_access_begin(encoder, owned_lane_mask);
+
if (intel_encoder_is_c10phy(encoder)) {
- intel_cx0_rmw(encoder, owned_lane_mask, PHY_C10_VDR_CONTROL(1),
- 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED);
intel_cx0_rmw(encoder, owned_lane_mask, PHY_C10_VDR_CMN(3),
C10_CMN3_TXVBOOST_MASK,
C10_CMN3_TXVBOOST(intel_c10_get_tx_vboost_lvl(crtc_state)),
@@ -508,9 +534,7 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
0, PHY_C10_VDR_OVRD_TX1 | PHY_C10_VDR_OVRD_TX2,
MB_WRITE_COMMITTED);
- if (intel_encoder_is_c10phy(encoder))
- intel_cx0_rmw(encoder, owned_lane_mask, PHY_C10_VDR_CONTROL(1),
- 0, C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_commit(encoder, owned_lane_mask, false);
intel_cx0_phy_transaction_end(encoder, wakeref);
}
@@ -2005,7 +2029,7 @@ static const struct intel_c20pll_state * const mtl_c20_hdmi_tables[] = {
};
static const struct intel_c10pll_state * const *
-intel_c10pll_tables_get(struct intel_crtc_state *crtc_state,
+intel_c10pll_tables_get(const struct intel_crtc_state *crtc_state,
struct intel_encoder *encoder)
{
if (intel_crtc_has_dp_encoder(crtc_state)) {
@@ -2035,6 +2059,15 @@ static void intel_cx0pll_update_ssc(struct intel_encoder *encoder,
}
}
+#define C10_PLL_SSC_REG_START_IDX 4
+#define C10_PLL_SSC_REG_COUNT 5
+
+static bool intel_c10pll_ssc_enabled(const struct intel_c10pll_state *pll_state)
+{
+ return memchr_inv(&pll_state->pll[C10_PLL_SSC_REG_START_IDX],
+ 0, sizeof(pll_state->pll[0]) * C10_PLL_SSC_REG_COUNT);
+}
+
static void intel_c10pll_update_pll(struct intel_encoder *encoder,
struct intel_cx0pll_state *pll_state)
{
@@ -2044,16 +2077,42 @@ static void intel_c10pll_update_pll(struct intel_encoder *encoder,
if (pll_state->ssc_enabled)
return;
- drm_WARN_ON(display->drm, ARRAY_SIZE(pll_state->c10.pll) < 9);
- for (i = 4; i < 9; i++)
+ drm_WARN_ON(display->drm, ARRAY_SIZE(pll_state->c10.pll) <
+ C10_PLL_SSC_REG_START_IDX + C10_PLL_SSC_REG_COUNT);
+ for (i = C10_PLL_SSC_REG_START_IDX;
+ i < C10_PLL_SSC_REG_START_IDX + C10_PLL_SSC_REG_COUNT;
+ i++)
pll_state->c10.pll[i] = 0;
}
+static bool c10pll_state_is_dp(const struct intel_c10pll_state *pll_state)
+{
+ return !REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]);
+}
+
+static bool c20pll_state_is_dp(const struct intel_c20pll_state *pll_state)
+{
+ return pll_state->vdr.serdes_rate & PHY_C20_IS_DP;
+}
+
+static bool cx0pll_state_is_dp(const struct intel_cx0pll_state *pll_state)
+{
+ if (pll_state->use_c10)
+ return c10pll_state_is_dp(&pll_state->c10);
+
+ return c20pll_state_is_dp(&pll_state->c20);
+}
+
+/*
+ * TODO: Convert the following to align with intel_c20pll_find_table() and
+ * intel_c20pll_calc_state_from_table().
+ */
static int intel_c10pll_calc_state_from_table(struct intel_encoder *encoder,
const struct intel_c10pll_state * const *tables,
- bool is_dp, int port_clock,
+ bool is_dp, int port_clock, int lane_count,
struct intel_cx0pll_state *pll_state)
{
+ struct intel_display *display = to_intel_display(encoder);
int i;
for (i = 0; tables[i]; i++) {
@@ -2061,7 +2120,11 @@ static int intel_c10pll_calc_state_from_table(struct intel_encoder *encoder,
pll_state->c10 = *tables[i];
intel_cx0pll_update_ssc(encoder, pll_state, is_dp);
intel_c10pll_update_pll(encoder, pll_state);
+
pll_state->use_c10 = true;
+ pll_state->lane_count = lane_count;
+
+ drm_WARN_ON(display->drm, is_dp != c10pll_state_is_dp(&pll_state->c10));
return 0;
}
@@ -2070,9 +2133,12 @@ static int intel_c10pll_calc_state_from_table(struct intel_encoder *encoder,
return -EINVAL;
}
-static int intel_c10pll_calc_state(struct intel_crtc_state *crtc_state,
- struct intel_encoder *encoder)
+static int intel_c10pll_calc_state(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder,
+ struct intel_dpll_hw_state *hw_state)
{
+ struct intel_display *display = to_intel_display(encoder);
+ bool is_dp = intel_crtc_has_dp_encoder(crtc_state);
const struct intel_c10pll_state * const *tables;
int err;
@@ -2080,43 +2146,126 @@ static int intel_c10pll_calc_state(struct intel_crtc_state *crtc_state,
if (!tables)
return -EINVAL;
- err = intel_c10pll_calc_state_from_table(encoder, tables,
- intel_crtc_has_dp_encoder(crtc_state),
- crtc_state->port_clock,
- &crtc_state->dpll_hw_state.cx0pll);
+ err = intel_c10pll_calc_state_from_table(encoder, tables, is_dp,
+ crtc_state->port_clock, crtc_state->lane_count,
+ &hw_state->cx0pll);
if (err == 0 || !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
return err;
/* For HDMI PLLs try SNPS PHY algorithm, if there are no precomputed tables */
- intel_snps_hdmi_pll_compute_c10pll(&crtc_state->dpll_hw_state.cx0pll.c10,
+ intel_snps_hdmi_pll_compute_c10pll(&hw_state->cx0pll.c10,
crtc_state->port_clock);
- intel_c10pll_update_pll(encoder,
- &crtc_state->dpll_hw_state.cx0pll);
- crtc_state->dpll_hw_state.cx0pll.use_c10 = true;
+ intel_c10pll_update_pll(encoder, &hw_state->cx0pll);
+
+ hw_state->cx0pll.use_c10 = true;
+ hw_state->cx0pll.lane_count = crtc_state->lane_count;
+
+ drm_WARN_ON(display->drm, is_dp != c10pll_state_is_dp(&hw_state->cx0pll.c10));
return 0;
}
static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder,
- const struct intel_c10pll_state *pll_state);
+ const struct intel_c10pll_state *pll_state)
+{
+ unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1;
+ unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400;
+ int tmpclk = 0;
+
+ if (pll_state->pll[0] & C10_PLL0_FRACEN) {
+ frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11];
+ frac_rem = pll_state->pll[14] << 8 | pll_state->pll[13];
+ frac_den = pll_state->pll[10] << 8 | pll_state->pll[9];
+ }
+
+ multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, pll_state->pll[3]) << 8 |
+ pll_state->pll[2]) / 2 + 16;
+
+ tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]);
+ hdmi_div = REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]);
+
+ tmpclk = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) +
+ DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den),
+ 10 << (tx_clk_div + 16));
+ tmpclk *= (hdmi_div ? 2 : 1);
+
+ return tmpclk;
+}
+
+static int readout_enabled_lane_count(struct intel_encoder *encoder)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ u8 enabled_tx_lane_count = 0;
+ int max_tx_lane_count = 4;
+ bool lane_reversal;
+ int tx_lane;
+
+ lane_reversal = intel_de_read(display, XELPDP_PORT_BUF_CTL1(display, encoder->port)) &
+ XELPDP_PORT_REVERSAL;
+
+ /*
+ * TODO: also check inactive TX lanes in all PHY lanes owned by the
+ * display. For now checking only those PHY lane(s) which are owned
+ * based on the active TX lane count (i.e.
+ * 1,2 active TX lanes -> PHY lane#0
+ * 3,4 active TX lanes -> PHY lane#0 and PHY lane#1).
+ *
+ * In case of lane reversal for 1, 2 active TX lanes, only PHY
+ * lane#1 is used. This is only possible in TypeC legacy mode or if
+ * the port is connected to a non-TC PHY. In both of these cases both
+ * PHY lane#0 and #1 are owned by display, so check all 4 TX lanes in
+ * both PHY lanes in those cases.
+ */
+ if (!lane_reversal)
+ max_tx_lane_count = DDI_PORT_WIDTH_GET(intel_de_read(display,
+ DDI_BUF_CTL(encoder->port)));
+
+ if (!drm_WARN_ON(display->drm, max_tx_lane_count == 0))
+ max_tx_lane_count = round_up(max_tx_lane_count, 2);
+
+ for (tx_lane = 0; tx_lane < max_tx_lane_count; tx_lane++) {
+ u8 phy_lane_mask = tx_lane < 2 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1;
+ int tx = tx_lane % 2 + 1;
+ u8 val;
+
+ val = intel_cx0_read(encoder, phy_lane_mask, PHY_CX0_TX_CONTROL(tx, 2));
+ if (!(val & CONTROL2_DISABLE_SINGLE_TX))
+ enabled_tx_lane_count++;
+ }
+
+ return enabled_tx_lane_count;
+}
+
+static bool readout_ssc_state(struct intel_encoder *encoder, bool is_mpll_b)
+{
+ struct intel_display *display = to_intel_display(encoder);
+
+ return intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port)) &
+ (is_mpll_b ? XELPDP_SSC_ENABLE_PLLB : XELPDP_SSC_ENABLE_PLLA);
+}
static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder,
- struct intel_c10pll_state *pll_state)
+ struct intel_cx0pll_state *cx0pll_state)
{
+ struct intel_c10pll_state *pll_state = &cx0pll_state->c10;
+ struct intel_display *display = to_intel_display(encoder);
+ enum phy phy = intel_encoder_to_phy(encoder);
u8 lane = INTEL_CX0_LANE0;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int i;
+ cx0pll_state->use_c10 = true;
+
wakeref = intel_cx0_phy_transaction_begin(encoder);
/*
* According to C10 VDR Register programming Sequence we need
* to do this to read PHY internal registers from MsgBus.
*/
- intel_cx0_rmw(encoder, lane, PHY_C10_VDR_CONTROL(1),
- 0, C10_VDR_CTRL_MSGBUS_ACCESS,
- MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_begin(encoder, lane);
+
+ cx0pll_state->lane_count = readout_enabled_lane_count(encoder);
for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++)
pll_state->pll[i] = intel_cx0_read(encoder, lane, PHY_C10_VDR_PLL(i));
@@ -2127,6 +2276,15 @@ static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder,
intel_cx0_phy_transaction_end(encoder, wakeref);
pll_state->clock = intel_c10pll_calc_port_clock(encoder, pll_state);
+
+ cx0pll_state->ssc_enabled = readout_ssc_state(encoder, true);
+
+ if (cx0pll_state->ssc_enabled != intel_c10pll_ssc_enabled(pll_state))
+ drm_dbg_kms(display->drm,
+ "PHY %c: SSC state mismatch: port SSC is %s, PLL SSC is %s\n",
+ phy_name(phy),
+ str_enabled_disabled(cx0pll_state->ssc_enabled),
+ str_enabled_disabled(intel_c10pll_ssc_enabled(pll_state)));
}
static void intel_c10_pll_program(struct intel_display *display,
@@ -2135,9 +2293,7 @@ static void intel_c10_pll_program(struct intel_display *display,
{
int i;
- intel_cx0_rmw(encoder, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1),
- 0, C10_VDR_CTRL_MSGBUS_ACCESS,
- MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_begin(encoder, INTEL_CX0_BOTH_LANES);
/* Program the pll values only for the master lane */
for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++)
@@ -2152,12 +2308,11 @@ static void intel_c10_pll_program(struct intel_display *display,
intel_cx0_rmw(encoder, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CUSTOM_WIDTH,
C10_VDR_CUSTOM_WIDTH_MASK, C10_VDR_CUSTOM_WIDTH_8_10,
MB_WRITE_COMMITTED);
- intel_cx0_rmw(encoder, INTEL_CX0_LANE0, PHY_C10_VDR_CONTROL(1),
- 0, C10_VDR_CTRL_MASTER_LANE | C10_VDR_CTRL_UPDATE_CFG,
- MB_WRITE_COMMITTED);
+
+ intel_c10_msgbus_access_commit(encoder, INTEL_CX0_LANE0, true);
}
-static void intel_c10pll_dump_hw_state(struct intel_display *display,
+static void intel_c10pll_dump_hw_state(struct drm_printer *p,
const struct intel_c10pll_state *hw_state)
{
bool fracen;
@@ -2166,33 +2321,32 @@ static void intel_c10pll_dump_hw_state(struct intel_display *display,
unsigned int multiplier, tx_clk_div;
fracen = hw_state->pll[0] & C10_PLL0_FRACEN;
- drm_dbg_kms(display->drm, "c10pll_hw_state: fracen: %s, ",
- str_yes_no(fracen));
+ drm_printf(p, "c10pll_hw_state: clock: %d, fracen: %s, ",
+ hw_state->clock, str_yes_no(fracen));
if (fracen) {
frac_quot = hw_state->pll[12] << 8 | hw_state->pll[11];
frac_rem = hw_state->pll[14] << 8 | hw_state->pll[13];
frac_den = hw_state->pll[10] << 8 | hw_state->pll[9];
- drm_dbg_kms(display->drm, "quot: %u, rem: %u, den: %u,\n",
- frac_quot, frac_rem, frac_den);
+ drm_printf(p, "quot: %u, rem: %u, den: %u,\n",
+ frac_quot, frac_rem, frac_den);
}
multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, hw_state->pll[3]) << 8 |
hw_state->pll[2]) / 2 + 16;
tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, hw_state->pll[15]);
- drm_dbg_kms(display->drm,
- "multiplier: %u, tx_clk_div: %u.\n", multiplier, tx_clk_div);
+ drm_printf(p,
+ "multiplier: %u, tx_clk_div: %u.\n", multiplier, tx_clk_div);
- drm_dbg_kms(display->drm, "c10pll_rawhw_state:");
- drm_dbg_kms(display->drm, "tx: 0x%x, cmn: 0x%x\n", hw_state->tx,
- hw_state->cmn);
+ drm_printf(p, "c10pll_rawhw_state:");
+ drm_printf(p, "tx: 0x%x, cmn: 0x%x\n", hw_state->tx, hw_state->cmn);
BUILD_BUG_ON(ARRAY_SIZE(hw_state->pll) % 4);
for (i = 0; i < ARRAY_SIZE(hw_state->pll); i = i + 4)
- drm_dbg_kms(display->drm,
- "pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x\n",
- i, hw_state->pll[i], i + 1, hw_state->pll[i + 1],
- i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]);
+ drm_printf(p,
+ "pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x\n",
+ i, hw_state->pll[i], i + 1, hw_state->pll[i + 1],
+ i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]);
}
/*
@@ -2210,7 +2364,7 @@ static bool is_arrowlake_s_by_host_bridge(void)
return pdev && IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(host_bridge_pci_dev_id);
}
-static u16 intel_c20_hdmi_tmds_tx_cgf_1(struct intel_crtc_state *crtc_state)
+static u16 intel_c20_hdmi_tmds_tx_cgf_1(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
u16 tx_misc;
@@ -2234,9 +2388,9 @@ static u16 intel_c20_hdmi_tmds_tx_cgf_1(struct intel_crtc_state *crtc_state)
C20_PHY_TX_DCC_BYPASS | C20_PHY_TX_TERM_CTL(tx_term_ctrl));
}
-static int intel_c20_compute_hdmi_tmds_pll(struct intel_crtc_state *crtc_state)
+static int intel_c20_compute_hdmi_tmds_pll(const struct intel_crtc_state *crtc_state,
+ struct intel_c20pll_state *pll_state)
{
- struct intel_c20pll_state *pll_state = &crtc_state->dpll_hw_state.cx0pll.c20;
u64 datarate;
u64 mpll_tx_clk_div;
u64 vco_freq_shift;
@@ -2304,7 +2458,7 @@ static int intel_c20_compute_hdmi_tmds_pll(struct intel_crtc_state *crtc_state)
}
static const struct intel_c20pll_state * const *
-intel_c20_pll_tables_get(struct intel_crtc_state *crtc_state,
+intel_c20_pll_tables_get(const struct intel_crtc_state *crtc_state,
struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(crtc_state);
@@ -2332,42 +2486,220 @@ intel_c20_pll_tables_get(struct intel_crtc_state *crtc_state,
return NULL;
}
-static int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state,
- struct intel_encoder *encoder)
+static u8 intel_c20_get_dp_rate(u32 clock)
{
- const struct intel_c20pll_state * const *tables;
- int i;
+ switch (clock) {
+ case 162000: /* 1.62 Gbps DP1.4 */
+ return 0;
+ case 270000: /* 2.7 Gbps DP1.4 */
+ return 1;
+ case 540000: /* 5.4 Gbps DP 1.4 */
+ return 2;
+ case 810000: /* 8.1 Gbps DP1.4 */
+ return 3;
+ case 216000: /* 2.16 Gbps eDP */
+ return 4;
+ case 243000: /* 2.43 Gbps eDP */
+ return 5;
+ case 324000: /* 3.24 Gbps eDP */
+ return 6;
+ case 432000: /* 4.32 Gbps eDP */
+ return 7;
+ case 1000000: /* 10 Gbps DP2.0 */
+ return 8;
+ case 1350000: /* 13.5 Gbps DP2.0 */
+ return 9;
+ case 2000000: /* 20 Gbps DP2.0 */
+ return 10;
+ case 648000: /* 6.48 Gbps eDP*/
+ return 11;
+ case 675000: /* 6.75 Gbps eDP*/
+ return 12;
+ default:
+ MISSING_CASE(clock);
+ return 0;
+ }
+}
- /* try computed C20 HDMI tables before using consolidated tables */
- if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
- if (intel_c20_compute_hdmi_tmds_pll(crtc_state) == 0)
- return 0;
+static u8 intel_c20_get_hdmi_rate(u32 clock)
+{
+ if (clock >= 25175 && clock <= 600000)
+ return 0;
+
+ switch (clock) {
+ case 300000: /* 3 Gbps */
+ case 600000: /* 6 Gbps */
+ case 1200000: /* 12 Gbps */
+ return 1;
+ case 800000: /* 8 Gbps */
+ return 2;
+ case 1000000: /* 10 Gbps */
+ return 3;
+ default:
+ MISSING_CASE(clock);
+ return 0;
}
+}
+
+static bool is_dp2(u32 clock)
+{
+ /* DP2.0 clock rates */
+ if (clock == 1000000 || clock == 1350000 || clock == 2000000)
+ return true;
+
+ return false;
+}
+
+static int intel_get_c20_custom_width(u32 clock, bool dp)
+{
+ if (dp && is_dp2(clock))
+ return 2;
+ else if (intel_hdmi_is_frl(clock))
+ return 1;
+ else
+ return 0;
+}
+
+static void intel_c20_calc_vdr_params(struct intel_c20pll_vdr_state *vdr, bool is_dp,
+ int port_clock)
+{
+ vdr->custom_width = intel_get_c20_custom_width(port_clock, is_dp);
+
+ vdr->serdes_rate = 0;
+ vdr->hdmi_rate = 0;
+
+ if (is_dp) {
+ vdr->serdes_rate = PHY_C20_IS_DP |
+ PHY_C20_DP_RATE(intel_c20_get_dp_rate(port_clock));
+ } else {
+ if (intel_hdmi_is_frl(port_clock))
+ vdr->serdes_rate = PHY_C20_IS_HDMI_FRL;
+
+ vdr->hdmi_rate = intel_c20_get_hdmi_rate(port_clock);
+ }
+}
+
+#define PHY_C20_SERDES_RATE_MASK (PHY_C20_IS_DP | PHY_C20_DP_RATE_MASK | PHY_C20_IS_HDMI_FRL)
+
+static void intel_c20_readout_vdr_params(struct intel_encoder *encoder,
+ struct intel_c20pll_vdr_state *vdr, bool *cntx)
+{
+ u8 serdes;
+
+ serdes = intel_cx0_read(encoder, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_SERDES_RATE);
+ *cntx = serdes & PHY_C20_CONTEXT_TOGGLE;
+
+ vdr->custom_width = intel_cx0_read(encoder, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_WIDTH) &
+ PHY_C20_CUSTOM_WIDTH_MASK;
+
+ vdr->serdes_rate = serdes & PHY_C20_SERDES_RATE_MASK;
+ if (!(vdr->serdes_rate & PHY_C20_IS_DP))
+ vdr->hdmi_rate = intel_cx0_read(encoder, INTEL_CX0_LANE0, PHY_C20_VDR_HDMI_RATE) &
+ PHY_C20_HDMI_RATE_MASK;
+ else
+ vdr->hdmi_rate = 0;
+}
+
+static void intel_c20_program_vdr_params(struct intel_encoder *encoder,
+ const struct intel_c20pll_vdr_state *vdr,
+ u8 owned_lane_mask)
+{
+ struct intel_display *display = to_intel_display(encoder);
+
+ drm_WARN_ON(display->drm, vdr->custom_width & ~PHY_C20_CUSTOM_WIDTH_MASK);
+ intel_cx0_rmw(encoder, owned_lane_mask, PHY_C20_VDR_CUSTOM_WIDTH,
+ PHY_C20_CUSTOM_WIDTH_MASK, vdr->custom_width,
+ MB_WRITE_COMMITTED);
+
+ drm_WARN_ON(display->drm, vdr->serdes_rate & ~PHY_C20_SERDES_RATE_MASK);
+ intel_cx0_rmw(encoder, owned_lane_mask, PHY_C20_VDR_CUSTOM_SERDES_RATE,
+ PHY_C20_SERDES_RATE_MASK, vdr->serdes_rate,
+ MB_WRITE_COMMITTED);
+
+ if (vdr->serdes_rate & PHY_C20_IS_DP)
+ return;
+
+ drm_WARN_ON(display->drm, vdr->hdmi_rate & ~PHY_C20_HDMI_RATE_MASK);
+ intel_cx0_rmw(encoder, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_HDMI_RATE,
+ PHY_C20_HDMI_RATE_MASK, vdr->hdmi_rate,
+ MB_WRITE_COMMITTED);
+}
+
+static const struct intel_c20pll_state *
+intel_c20_pll_find_table(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ const struct intel_c20pll_state * const *tables;
+ int i;
tables = intel_c20_pll_tables_get(crtc_state, encoder);
if (!tables)
+ return NULL;
+
+ for (i = 0; tables[i]; i++)
+ if (crtc_state->port_clock == tables[i]->clock)
+ return tables[i];
+
+ return NULL;
+}
+
+static int intel_c20pll_calc_state_from_table(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder,
+ struct intel_cx0pll_state *pll_state)
+{
+ const struct intel_c20pll_state *table;
+
+ table = intel_c20_pll_find_table(crtc_state, encoder);
+ if (!table)
return -EINVAL;
- for (i = 0; tables[i]; i++) {
- if (crtc_state->port_clock == tables[i]->clock) {
- crtc_state->dpll_hw_state.cx0pll.c20 = *tables[i];
- intel_cx0pll_update_ssc(encoder,
- &crtc_state->dpll_hw_state.cx0pll,
- intel_crtc_has_dp_encoder(crtc_state));
- crtc_state->dpll_hw_state.cx0pll.use_c10 = false;
- return 0;
- }
- }
+ pll_state->c20 = *table;
- return -EINVAL;
+ intel_cx0pll_update_ssc(encoder, pll_state, intel_crtc_has_dp_encoder(crtc_state));
+
+ return 0;
+}
+
+static int intel_c20pll_calc_state(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder,
+ struct intel_dpll_hw_state *hw_state)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ bool is_dp = intel_crtc_has_dp_encoder(crtc_state);
+ int err = -ENOENT;
+
+ hw_state->cx0pll.use_c10 = false;
+ hw_state->cx0pll.lane_count = crtc_state->lane_count;
+
+ /* try computed C20 HDMI tables before using consolidated tables */
+ if (!is_dp)
+ /* TODO: Update SSC state for HDMI as well */
+ err = intel_c20_compute_hdmi_tmds_pll(crtc_state, &hw_state->cx0pll.c20);
+
+ if (err)
+ err = intel_c20pll_calc_state_from_table(crtc_state, encoder,
+ &hw_state->cx0pll);
+
+ if (err)
+ return err;
+
+ intel_c20_calc_vdr_params(&hw_state->cx0pll.c20.vdr,
+ is_dp, crtc_state->port_clock);
+
+ drm_WARN_ON(display->drm, is_dp != c20pll_state_is_dp(&hw_state->cx0pll.c20));
+
+ return 0;
}
-int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state,
- struct intel_encoder *encoder)
+int intel_cx0pll_calc_state(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder,
+ struct intel_dpll_hw_state *hw_state)
{
+ memset(hw_state, 0, sizeof(*hw_state));
+
if (intel_encoder_is_c10phy(encoder))
- return intel_c10pll_calc_state(crtc_state, encoder);
- return intel_c20pll_calc_state(crtc_state, encoder);
+ return intel_c10pll_calc_state(crtc_state, encoder, hw_state);
+ return intel_c20pll_calc_state(crtc_state, encoder, hw_state);
}
static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state)
@@ -2421,17 +2753,22 @@ static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder,
}
static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder,
- struct intel_c20pll_state *pll_state)
+ struct intel_cx0pll_state *cx0pll_state)
{
+ struct intel_c20pll_state *pll_state = &cx0pll_state->c20;
struct intel_display *display = to_intel_display(encoder);
bool cntx;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int i;
+ cx0pll_state->use_c10 = false;
+
wakeref = intel_cx0_phy_transaction_begin(encoder);
- /* 1. Read current context selection */
- cntx = intel_cx0_read(encoder, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_SERDES_RATE) & PHY_C20_CONTEXT_TOGGLE;
+ cx0pll_state->lane_count = readout_enabled_lane_count(encoder);
+
+ /* 1. Read VDR params and current context selection */
+ intel_c20_readout_vdr_params(encoder, &pll_state->vdr, &cntx);
/* Read Tx configuration */
for (i = 0; i < ARRAY_SIZE(pll_state->tx); i++) {
@@ -2486,103 +2823,52 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder,
pll_state->clock = intel_c20pll_calc_port_clock(encoder, pll_state);
intel_cx0_phy_transaction_end(encoder, wakeref);
+
+ cx0pll_state->ssc_enabled = readout_ssc_state(encoder, intel_c20phy_use_mpllb(pll_state));
}
-static void intel_c20pll_dump_hw_state(struct intel_display *display,
+static void intel_c20pll_dump_hw_state(struct drm_printer *p,
const struct intel_c20pll_state *hw_state)
{
int i;
- drm_dbg_kms(display->drm, "c20pll_hw_state:\n");
- drm_dbg_kms(display->drm,
- "tx[0] = 0x%.4x, tx[1] = 0x%.4x, tx[2] = 0x%.4x\n",
- hw_state->tx[0], hw_state->tx[1], hw_state->tx[2]);
- drm_dbg_kms(display->drm,
- "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n",
- hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]);
+ drm_printf(p, "c20pll_hw_state: clock: %d\n", hw_state->clock);
+ drm_printf(p,
+ "tx[0] = 0x%.4x, tx[1] = 0x%.4x, tx[2] = 0x%.4x\n",
+ hw_state->tx[0], hw_state->tx[1], hw_state->tx[2]);
+ drm_printf(p,
+ "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n",
+ hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]);
if (intel_c20phy_use_mpllb(hw_state)) {
for (i = 0; i < ARRAY_SIZE(hw_state->mpllb); i++)
- drm_dbg_kms(display->drm, "mpllb[%d] = 0x%.4x\n", i,
- hw_state->mpllb[i]);
+ drm_printf(p, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]);
} else {
for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++)
- drm_dbg_kms(display->drm, "mplla[%d] = 0x%.4x\n", i,
- hw_state->mplla[i]);
- }
-}
+ drm_printf(p, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]);
-void intel_cx0pll_dump_hw_state(struct intel_display *display,
- const struct intel_cx0pll_state *hw_state)
-{
- if (hw_state->use_c10)
- intel_c10pll_dump_hw_state(display, &hw_state->c10);
- else
- intel_c20pll_dump_hw_state(display, &hw_state->c20);
-}
-
-static u8 intel_c20_get_dp_rate(u32 clock)
-{
- switch (clock) {
- case 162000: /* 1.62 Gbps DP1.4 */
- return 0;
- case 270000: /* 2.7 Gbps DP1.4 */
- return 1;
- case 540000: /* 5.4 Gbps DP 1.4 */
- return 2;
- case 810000: /* 8.1 Gbps DP1.4 */
- return 3;
- case 216000: /* 2.16 Gbps eDP */
- return 4;
- case 243000: /* 2.43 Gbps eDP */
- return 5;
- case 324000: /* 3.24 Gbps eDP */
- return 6;
- case 432000: /* 4.32 Gbps eDP */
- return 7;
- case 1000000: /* 10 Gbps DP2.0 */
- return 8;
- case 1350000: /* 13.5 Gbps DP2.0 */
- return 9;
- case 2000000: /* 20 Gbps DP2.0 */
- return 10;
- case 648000: /* 6.48 Gbps eDP*/
- return 11;
- case 675000: /* 6.75 Gbps eDP*/
- return 12;
- default:
- MISSING_CASE(clock);
- return 0;
+ /* For full coverage, also print the additional PLL B entry. */
+ BUILD_BUG_ON(ARRAY_SIZE(hw_state->mplla) + 1 != ARRAY_SIZE(hw_state->mpllb));
+ drm_printf(p, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]);
}
-}
-static u8 intel_c20_get_hdmi_rate(u32 clock)
-{
- if (clock >= 25175 && clock <= 600000)
- return 0;
-
- switch (clock) {
- case 300000: /* 3 Gbps */
- case 600000: /* 6 Gbps */
- case 1200000: /* 12 Gbps */
- return 1;
- case 800000: /* 8 Gbps */
- return 2;
- case 1000000: /* 10 Gbps */
- return 3;
- default:
- MISSING_CASE(clock);
- return 0;
- }
+ drm_printf(p,
+ "vdr: custom width: 0x%02x, serdes rate: 0x%02x, hdmi rate: 0x%02x\n",
+ hw_state->vdr.custom_width, hw_state->vdr.serdes_rate, hw_state->vdr.hdmi_rate);
}
-static bool is_dp2(u32 clock)
+void intel_cx0pll_dump_hw_state(struct drm_printer *p,
+ const struct intel_cx0pll_state *hw_state)
{
- /* DP2.0 clock rates */
- if (clock == 1000000 || clock == 1350000 || clock == 2000000)
- return true;
+ drm_printf(p,
+ "cx0pll_hw_state: lane_count: %d, ssc_enabled: %s, use_c10: %s, tbt_mode: %s\n",
+ hw_state->lane_count, str_yes_no(hw_state->ssc_enabled),
+ str_yes_no(hw_state->use_c10), str_yes_no(hw_state->tbt_mode));
- return false;
+ if (hw_state->use_c10)
+ intel_c10pll_dump_hw_state(p, &hw_state->c10);
+ else
+ intel_c20pll_dump_hw_state(p, &hw_state->c20);
}
static bool intel_c20_protocol_switch_valid(struct intel_encoder *encoder)
@@ -2594,23 +2880,11 @@ static bool intel_c20_protocol_switch_valid(struct intel_encoder *encoder)
return intel_tc_port_in_legacy_mode(intel_dig_port);
}
-static int intel_get_c20_custom_width(u32 clock, bool dp)
-{
- if (dp && is_dp2(clock))
- return 2;
- else if (intel_hdmi_is_frl(clock))
- return 1;
- else
- return 0;
-}
-
static void intel_c20_pll_program(struct intel_display *display,
struct intel_encoder *encoder,
- const struct intel_c20pll_state *pll_state,
- bool is_dp, int port_clock)
+ const struct intel_c20pll_state *pll_state)
{
u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(encoder);
- u8 serdes;
bool cntx;
int i;
@@ -2679,30 +2953,11 @@ static void intel_c20_pll_program(struct intel_display *display,
}
}
- /* 4. Program custom width to match the link protocol */
- intel_cx0_rmw(encoder, owned_lane_mask, PHY_C20_VDR_CUSTOM_WIDTH,
- PHY_C20_CUSTOM_WIDTH_MASK,
- PHY_C20_CUSTOM_WIDTH(intel_get_c20_custom_width(port_clock, is_dp)),
- MB_WRITE_COMMITTED);
-
- /* 5. For DP or 6. For HDMI */
- serdes = 0;
- if (is_dp)
- serdes = PHY_C20_IS_DP |
- PHY_C20_DP_RATE(intel_c20_get_dp_rate(port_clock));
- else if (intel_hdmi_is_frl(port_clock))
- serdes = PHY_C20_IS_HDMI_FRL;
-
- intel_cx0_rmw(encoder, owned_lane_mask, PHY_C20_VDR_CUSTOM_SERDES_RATE,
- PHY_C20_IS_DP | PHY_C20_DP_RATE_MASK | PHY_C20_IS_HDMI_FRL,
- serdes,
- MB_WRITE_COMMITTED);
-
- if (!is_dp)
- intel_cx0_rmw(encoder, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_HDMI_RATE,
- PHY_C20_HDMI_RATE_MASK,
- intel_c20_get_hdmi_rate(port_clock),
- MB_WRITE_COMMITTED);
+ /*
+ * 4. Program custom width to match the link protocol.
+ * 5. For DP or 6. For HDMI
+ */
+ intel_c20_program_vdr_params(encoder, &pll_state->vdr, owned_lane_mask);
/*
* 7. Write Vendor specific registers to toggle context setting to load
@@ -2713,39 +2968,13 @@ static void intel_c20_pll_program(struct intel_display *display,
MB_WRITE_COMMITTED);
}
-static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder,
- const struct intel_c10pll_state *pll_state)
-{
- unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1;
- unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400;
- int tmpclk = 0;
-
- if (pll_state->pll[0] & C10_PLL0_FRACEN) {
- frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11];
- frac_rem = pll_state->pll[14] << 8 | pll_state->pll[13];
- frac_den = pll_state->pll[10] << 8 | pll_state->pll[9];
- }
-
- multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, pll_state->pll[3]) << 8 |
- pll_state->pll[2]) / 2 + 16;
-
- tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]);
- hdmi_div = REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]);
-
- tmpclk = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) +
- DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den),
- 10 << (tx_clk_div + 16));
- tmpclk *= (hdmi_div ? 2 : 1);
-
- return tmpclk;
-}
-
static void intel_program_port_clock_ctl(struct intel_encoder *encoder,
const struct intel_cx0pll_state *pll_state,
- bool is_dp, int port_clock,
+ int port_clock,
bool lane_reversal)
{
struct intel_display *display = to_intel_display(encoder);
+ bool is_dp = cx0pll_state_is_dp(pll_state);
u32 val = 0;
intel_de_rmw(display, XELPDP_PORT_BUF_CTL1(display, encoder->port),
@@ -2830,7 +3059,7 @@ void intel_cx0_powerdown_change_sequence(struct intel_encoder *encoder,
intel_cx0_get_powerdown_update(lane_mask),
XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_MS))
drm_warn(display->drm,
- "PHY %c failed to bring out of lane reset\n",
+ "PHY %c failed to change powerdown state\n",
phy_name(phy));
}
@@ -2938,11 +3167,7 @@ static void intel_cx0_program_phy_lane(struct intel_encoder *encoder, int lane_c
bool dp_alt_mode = intel_tc_port_in_dp_alt_mode(enc_to_dig_port(encoder));
u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(encoder);
- if (intel_encoder_is_c10phy(encoder))
- intel_cx0_rmw(encoder, owned_lane_mask,
- PHY_C10_VDR_CONTROL(1), 0,
- C10_VDR_CTRL_MSGBUS_ACCESS,
- MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_begin(encoder, owned_lane_mask);
if (lane_reversal)
disables = REG_GENMASK8(3, 0) >> lane_count;
@@ -2967,11 +3192,7 @@ static void intel_cx0_program_phy_lane(struct intel_encoder *encoder, int lane_c
MB_WRITE_COMMITTED);
}
- if (intel_encoder_is_c10phy(encoder))
- intel_cx0_rmw(encoder, owned_lane_mask,
- PHY_C10_VDR_CONTROL(1), 0,
- C10_VDR_CTRL_UPDATE_CFG,
- MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_commit(encoder, owned_lane_mask, false);
}
static u32 intel_cx0_get_pclk_pll_request(u8 lane_mask)
@@ -2996,23 +3217,30 @@ static u32 intel_cx0_get_pclk_pll_ack(u8 lane_mask)
return val;
}
-static void __intel_cx0pll_enable(struct intel_encoder *encoder,
- const struct intel_cx0pll_state *pll_state,
- bool is_dp, int port_clock, int lane_count)
+static void intel_cx0pll_enable(struct intel_encoder *encoder,
+ const struct intel_cx0pll_state *pll_state)
{
+ int port_clock = pll_state->use_c10 ? pll_state->c10.clock : pll_state->c20.clock;
struct intel_display *display = to_intel_display(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool lane_reversal = dig_port->lane_reversal;
u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 :
INTEL_CX0_LANE0;
- intel_wakeref_t wakeref = intel_cx0_phy_transaction_begin(encoder);
+ struct ref_tracker *wakeref = intel_cx0_phy_transaction_begin(encoder);
+
+ /*
+ * Lane reversal is never used in DP-alt mode, in that case the
+ * corresponding lane swapping (based on the TypeC cable flip state
+ * for instance) is handled automatically by the HW via a TCSS mux.
+ */
+ drm_WARN_ON(display->drm, lane_reversal && intel_tc_port_in_dp_alt_mode(dig_port));
/*
* 1. Program PORT_CLOCK_CTL REGISTER to configure
* clock muxes, gating and SSC
*/
- intel_program_port_clock_ctl(encoder, pll_state, is_dp, port_clock, lane_reversal);
+ intel_program_port_clock_ctl(encoder, pll_state, port_clock, lane_reversal);
/* 2. Bring PHY out of reset. */
intel_cx0_phy_lane_reset(encoder, lane_reversal);
@@ -3034,13 +3262,13 @@ static void __intel_cx0pll_enable(struct intel_encoder *encoder,
if (intel_encoder_is_c10phy(encoder))
intel_c10_pll_program(display, encoder, &pll_state->c10);
else
- intel_c20_pll_program(display, encoder, &pll_state->c20, is_dp, port_clock);
+ intel_c20_pll_program(display, encoder, &pll_state->c20);
/*
* 6. Program the enabled and disabled owned PHY lane
* transmitters over message bus
*/
- intel_cx0_program_phy_lane(encoder, lane_count, lane_reversal);
+ intel_cx0_program_phy_lane(encoder, pll_state->lane_count, lane_reversal);
/*
* 7. Follow the Display Voltage Frequency Switching - Sequence
@@ -3074,16 +3302,40 @@ static void __intel_cx0pll_enable(struct intel_encoder *encoder,
* Frequency Change. We handle this step in bxt_set_cdclk().
*/
- /* TODO: enable TBT-ALT mode */
+ /*
+ * 12. Toggle powerdown if HDMI is enabled on C10 PHY.
+ *
+ * Wa_13013502646:
+ * Fixes: HDMI lane to lane skew violations on C10 display PHYs.
+ * Workaround: Toggle powerdown value by setting first to P0 and then to P2, for both
+ * PHY lanes.
+ */
+ if (!cx0pll_state_is_dp(pll_state) && pll_state->use_c10) {
+ intel_cx0_powerdown_change_sequence(encoder, INTEL_CX0_BOTH_LANES,
+ XELPDP_P0_STATE_ACTIVE);
+ intel_cx0_powerdown_change_sequence(encoder, INTEL_CX0_BOTH_LANES,
+ XELPDP_P2_STATE_READY);
+ }
+
intel_cx0_phy_transaction_end(encoder, wakeref);
}
-static void intel_cx0pll_enable(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+void intel_mtl_tbt_pll_calc_state(struct intel_dpll_hw_state *hw_state)
{
- __intel_cx0pll_enable(encoder, &crtc_state->dpll_hw_state.cx0pll,
- intel_crtc_has_dp_encoder(crtc_state),
- crtc_state->port_clock, crtc_state->lane_count);
+ memset(hw_state, 0, sizeof(*hw_state));
+
+ hw_state->cx0pll.tbt_mode = true;
+}
+
+bool intel_mtl_tbt_pll_readout_hw_state(struct intel_display *display,
+ struct intel_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ memset(hw_state, 0, sizeof(*hw_state));
+
+ hw_state->cx0pll.tbt_mode = true;
+
+ return true;
}
int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder)
@@ -3148,8 +3400,7 @@ static int intel_mtl_tbt_clock_select(struct intel_display *display,
}
}
-void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+void intel_mtl_tbt_pll_enable_clock(struct intel_encoder *encoder, int port_clock)
{
struct intel_display *display = to_intel_display(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
@@ -3163,7 +3414,7 @@ void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
mask = XELPDP_DDI_CLOCK_SELECT_MASK(display);
val |= XELPDP_DDI_CLOCK_SELECT_PREP(display,
- intel_mtl_tbt_clock_select(display, crtc_state->port_clock));
+ intel_mtl_tbt_clock_select(display, port_clock));
mask |= XELPDP_FORWARD_CLOCK_UNGATE;
val |= XELPDP_FORWARD_CLOCK_UNGATE;
@@ -3201,18 +3452,23 @@ void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder,
* clock frequency.
*/
intel_de_write(display, DDI_CLK_VALFREQ(encoder->port),
- crtc_state->port_clock);
+ port_clock);
}
void intel_mtl_pll_enable(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ intel_cx0pll_enable(encoder, &dpll_hw_state->cx0pll);
+}
+
+void intel_mtl_pll_enable_clock(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (intel_tc_port_in_tbt_alt_mode(dig_port))
- intel_mtl_tbt_pll_enable(encoder, crtc_state);
- else
- intel_cx0pll_enable(encoder, crtc_state);
+ intel_mtl_tbt_pll_enable_clock(encoder, crtc_state->port_clock);
}
/*
@@ -3224,7 +3480,7 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int i;
u8 owned_lane_mask;
@@ -3236,9 +3492,7 @@ void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder,
wakeref = intel_cx0_phy_transaction_begin(encoder);
- if (intel_encoder_is_c10phy(encoder))
- intel_cx0_rmw(encoder, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0,
- C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED);
+ intel_c10_msgbus_access_begin(encoder, owned_lane_mask);
for (i = 0; i < 4; i++) {
int tx = i % 2 + 1;
@@ -3273,7 +3527,7 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
- intel_wakeref_t wakeref = intel_cx0_phy_transaction_begin(encoder);
+ struct ref_tracker *wakeref = intel_cx0_phy_transaction_begin(encoder);
/* 1. Change owned PHY lane power to Disable state. */
intel_cx0_powerdown_change_sequence(encoder, INTEL_CX0_BOTH_LANES,
@@ -3329,7 +3583,7 @@ static bool intel_cx0_pll_is_enabled(struct intel_encoder *encoder)
intel_cx0_get_pclk_pll_request(lane);
}
-void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
+void intel_mtl_tbt_pll_disable_clock(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
@@ -3369,12 +3623,15 @@ void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
void intel_mtl_pll_disable(struct intel_encoder *encoder)
{
+ intel_cx0pll_disable(encoder);
+}
+
+void intel_mtl_pll_disable_clock(struct intel_encoder *encoder)
+{
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (intel_tc_port_in_tbt_alt_mode(dig_port))
- intel_mtl_tbt_pll_disable(encoder);
- else
- intel_cx0pll_disable(encoder);
+ intel_mtl_tbt_pll_disable_clock(encoder);
}
enum icl_port_dpll_id
@@ -3398,50 +3655,20 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder,
return ICL_PORT_DPLL_DEFAULT;
}
-static void intel_c10pll_state_verify(const struct intel_crtc_state *state,
- struct intel_crtc *crtc,
- struct intel_encoder *encoder,
- struct intel_c10pll_state *mpllb_hw_state)
-{
- struct intel_display *display = to_intel_display(state);
- const struct intel_c10pll_state *mpllb_sw_state = &state->dpll_hw_state.cx0pll.c10;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) {
- u8 expected = mpllb_sw_state->pll[i];
-
- INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->pll[i] != expected,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name, i,
- expected, mpllb_hw_state->pll[i]);
- }
-
- INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->tx != mpllb_sw_state->tx,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name,
- mpllb_sw_state->tx, mpllb_hw_state->tx);
-
- INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->cmn != mpllb_sw_state->cmn,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name,
- mpllb_sw_state->cmn, mpllb_hw_state->cmn);
-}
-
-void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder,
+bool intel_cx0pll_readout_hw_state(struct intel_encoder *encoder,
struct intel_cx0pll_state *pll_state)
{
- pll_state->use_c10 = false;
+ memset(pll_state, 0, sizeof(*pll_state));
- pll_state->tbt_mode = intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder));
- if (pll_state->tbt_mode)
- return;
+ if (!intel_cx0_pll_is_enabled(encoder))
+ return false;
- if (intel_encoder_is_c10phy(encoder)) {
- intel_c10pll_readout_hw_state(encoder, &pll_state->c10);
- pll_state->use_c10 = true;
- } else {
- intel_c20pll_readout_hw_state(encoder, &pll_state->c20);
- }
+ if (intel_encoder_is_c10phy(encoder))
+ intel_c10pll_readout_hw_state(encoder, pll_state);
+ else
+ intel_c20pll_readout_hw_state(encoder, pll_state);
+
+ return true;
}
static bool mtl_compare_hw_state_c10(const struct intel_c10pll_state *a,
@@ -3505,91 +3732,6 @@ int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder,
return intel_c20pll_calc_port_clock(encoder, &pll_state->c20);
}
-static void intel_c20pll_state_verify(const struct intel_crtc_state *state,
- struct intel_crtc *crtc,
- struct intel_encoder *encoder,
- struct intel_c20pll_state *mpll_hw_state)
-{
- struct intel_display *display = to_intel_display(state);
- const struct intel_c20pll_state *mpll_sw_state = &state->dpll_hw_state.cx0pll.c20;
- bool sw_use_mpllb = intel_c20phy_use_mpllb(mpll_sw_state);
- bool hw_use_mpllb = intel_c20phy_use_mpllb(mpll_hw_state);
- int clock = intel_c20pll_calc_port_clock(encoder, mpll_sw_state);
- int i;
-
- INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->clock != clock,
- "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)",
- crtc->base.base.id, crtc->base.name,
- mpll_sw_state->clock, mpll_hw_state->clock);
-
- INTEL_DISPLAY_STATE_WARN(display, sw_use_mpllb != hw_use_mpllb,
- "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)",
- crtc->base.base.id, crtc->base.name,
- sw_use_mpllb, hw_use_mpllb);
-
- if (hw_use_mpllb) {
- for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) {
- INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i],
- "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]);
- }
- } else {
- for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) {
- INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i],
- "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]);
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) {
- INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->tx[i] != mpll_sw_state->tx[i],
- "[CRTC:%d:%s] mismatch in C20: Register TX[%i] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->tx[i], mpll_hw_state->tx[i]);
- }
-
- for (i = 0; i < ARRAY_SIZE(mpll_sw_state->cmn); i++) {
- INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->cmn[i] != mpll_sw_state->cmn[i],
- "[CRTC:%d:%s] mismatch in C20: Register CMN[%i] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->cmn[i], mpll_hw_state->cmn[i]);
- }
-}
-
-void intel_cx0pll_state_verify(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
-{
- struct intel_display *display = to_intel_display(state);
- const struct intel_crtc_state *new_crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
- struct intel_encoder *encoder;
- struct intel_cx0pll_state mpll_hw_state = {};
-
- if (!IS_DISPLAY_VER(display, 14, 30))
- return;
-
- if (!new_crtc_state->hw.active)
- return;
-
- /* intel_get_crtc_new_encoder() only works for modeset/fastset commits */
- if (!intel_crtc_needs_modeset(new_crtc_state) &&
- !intel_crtc_needs_fastset(new_crtc_state))
- return;
-
- encoder = intel_get_crtc_new_encoder(state, new_crtc_state);
- intel_cx0pll_readout_hw_state(encoder, &mpll_hw_state);
-
- if (mpll_hw_state.tbt_mode)
- return;
-
- if (intel_encoder_is_c10phy(encoder))
- intel_c10pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c10);
- else
- intel_c20pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c20);
-}
-
/*
* WA 14022081154
* The dedicated display PHYs reset to a power state that blocks S0ix, increasing idle
@@ -3613,6 +3755,7 @@ void intel_cx0_pll_power_save_wa(struct intel_display *display)
for_each_intel_encoder(display->drm, encoder) {
struct intel_cx0pll_state pll_state = {};
int port_clock = 162000;
+ int lane_count = 4;
if (!intel_encoder_is_dig_port(encoder))
continue;
@@ -3625,7 +3768,7 @@ void intel_cx0_pll_power_save_wa(struct intel_display *display)
if (intel_c10pll_calc_state_from_table(encoder,
mtl_c10_edp_tables,
- true, port_clock,
+ true, port_clock, lane_count,
&pll_state) < 0) {
drm_WARN_ON(display->drm,
"Unable to calc C10 state from the tables\n");
@@ -3636,7 +3779,7 @@ void intel_cx0_pll_power_save_wa(struct intel_display *display)
"[ENCODER:%d:%s] Applying power saving workaround on disabled PLL\n",
encoder->base.base.id, encoder->base.name);
- __intel_cx0pll_enable(encoder, &pll_state, true, port_clock, 4);
+ intel_cx0pll_enable(encoder, &pll_state);
intel_cx0pll_disable(encoder);
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
index 84d334b865f7..9f10113e2d18 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
@@ -11,6 +11,7 @@
#define MB_WRITE_COMMITTED true
#define MB_WRITE_UNCOMMITTED false
+struct drm_printer;
enum icl_port_dpll_id;
struct intel_atomic_state;
struct intel_c10pll_state;
@@ -19,6 +20,8 @@ struct intel_crtc;
struct intel_crtc_state;
struct intel_cx0pll_state;
struct intel_display;
+struct intel_dpll;
+struct intel_dpll_hw_state;
struct intel_encoder;
struct intel_hdmi;
@@ -26,22 +29,30 @@ void intel_clear_response_ready_flag(struct intel_encoder *encoder,
int lane);
bool intel_encoder_is_c10phy(struct intel_encoder *encoder);
void intel_mtl_pll_enable(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state);
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state);
void intel_mtl_pll_disable(struct intel_encoder *encoder);
enum icl_port_dpll_id
intel_mtl_port_pll_type(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
+void intel_mtl_pll_enable_clock(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
+void intel_mtl_pll_disable_clock(struct intel_encoder *encoder);
+void intel_mtl_pll_disable_clock(struct intel_encoder *encoder);
+void intel_mtl_tbt_pll_enable_clock(struct intel_encoder *encoder,
+ int port_clock);
+void intel_mtl_tbt_pll_disable_clock(struct intel_encoder *encoder);
-int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder);
-void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder,
+int intel_cx0pll_calc_state(const struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder,
+ struct intel_dpll_hw_state *hw_state);
+bool intel_cx0pll_readout_hw_state(struct intel_encoder *encoder,
struct intel_cx0pll_state *pll_state);
int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder,
const struct intel_cx0pll_state *pll_state);
-void intel_cx0pll_dump_hw_state(struct intel_display *display,
+void intel_cx0pll_dump_hw_state(struct drm_printer *p,
const struct intel_cx0pll_state *hw_state);
-void intel_cx0pll_state_verify(struct intel_atomic_state *state,
- struct intel_crtc *crtc);
bool intel_cx0pll_compare_hw_state(const struct intel_cx0pll_state *a,
const struct intel_cx0pll_state *b);
void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
@@ -59,7 +70,13 @@ void intel_cx0_write(struct intel_encoder *encoder,
int intel_cx0_wait_for_ack(struct intel_encoder *encoder,
int command, int lane, u32 *val);
void intel_cx0_bus_reset(struct intel_encoder *encoder, int lane);
+
+void intel_mtl_tbt_pll_calc_state(struct intel_dpll_hw_state *hw_state);
+bool intel_mtl_tbt_pll_readout_hw_state(struct intel_display *display,
+ struct intel_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder);
+
void intel_cx0_pll_power_save_wa(struct intel_display *display);
void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 002ccd47856d..cb91d07cdaa6 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -89,6 +89,8 @@
#include "skl_scaler.h"
#include "skl_universal_plane.h"
+struct intel_dpll;
+
static const u8 index_to_dp_signal_levels[] = {
[0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0,
[1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1,
@@ -726,7 +728,7 @@ int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder,
bool enable, u32 hdcp_mask)
{
struct intel_display *display = to_intel_display(intel_encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int ret = 0;
wakeref = intel_display_power_get_if_enabled(display,
@@ -747,7 +749,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
int type = intel_connector->base.connector_type;
enum port port = encoder->port;
enum transcoder cpu_transcoder;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum pipe pipe = 0;
u32 ddi_mode;
bool ret;
@@ -803,7 +805,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
enum port port = encoder->port;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum pipe p;
u32 tmp;
u8 mst_pipe_mask = 0, dp128b132b_pipe_mask = 0;
@@ -846,7 +848,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
for_each_pipe(display, p) {
enum transcoder cpu_transcoder = (enum transcoder)p;
u32 port_mask, ddi_select, ddi_mode;
- intel_wakeref_t trans_wakeref;
+ struct ref_tracker *trans_wakeref;
trans_wakeref = intel_display_power_get_if_enabled(display,
POWER_DOMAIN_TRANSCODER(cpu_transcoder));
@@ -1000,7 +1002,7 @@ main_link_aux_power_domain_put(struct intel_digital_port *dig_port,
struct intel_display *display = to_intel_display(dig_port);
enum intel_display_power_domain domain =
intel_ddi_main_link_aux_domain(dig_port, crtc_state);
- intel_wakeref_t wf;
+ struct ref_tracker *wf;
wf = fetch_and_zero(&dig_port->aux_wakeref);
if (!wf)
@@ -2446,7 +2448,7 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder,
return;
}
- drm_err(display->drm, "Failed to enable FEC after retries\n");
+ drm_dbg_kms(display->drm, "Failed to enable FEC after retries\n");
}
static void intel_ddi_disable_fec(struct intel_encoder *encoder,
@@ -3128,7 +3130,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
struct intel_display *display = to_intel_display(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &dig_port->dp;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool is_mst = intel_crtc_has_type(old_crtc_state,
INTEL_OUTPUT_DP_MST);
@@ -3196,7 +3198,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state,
struct intel_display *display = to_intel_display(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
dig_port->set_infoframes(encoder, false,
old_crtc_state, old_conn_state);
@@ -3667,8 +3669,8 @@ void intel_ddi_update_active_dpll(struct intel_atomic_state *state,
intel_atomic_get_new_crtc_state(state, crtc);
struct intel_crtc *pipe_crtc;
- /* FIXME: Add MTL pll_mgr */
- if (DISPLAY_VER(display) >= 14 || !intel_encoder_is_tc(encoder))
+ /* FIXME: Add NVL+ and DG2 pll_mgr */
+ if (!intel_encoder_is_tc(encoder) || !display->dpll.mgr)
return;
for_each_intel_crtc_in_pipe_mask(display->drm, pipe_crtc,
@@ -3963,7 +3965,7 @@ static void bdw_get_trans_port_sync_config(struct intel_crtc_state *crtc_state)
for_each_cpu_transcoder_masked(display, cpu_transcoder, transcoders) {
enum intel_display_power_domain power_domain;
- intel_wakeref_t trans_wakeref;
+ struct ref_tracker *trans_wakeref;
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
trans_wakeref = intel_display_power_get_if_enabled(display,
@@ -4255,19 +4257,70 @@ static void xe3plpd_ddi_get_config(struct intel_encoder *encoder,
intel_ddi_get_config(encoder, crtc_state);
}
-static void mtl_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state)
+static bool icl_ddi_tc_pll_is_tbt(const struct intel_dpll *pll)
{
- intel_cx0pll_readout_hw_state(encoder, &crtc_state->dpll_hw_state.cx0pll);
+ return pll->info->id == DPLL_ID_ICL_TBTPLL;
+}
- if (crtc_state->dpll_hw_state.cx0pll.tbt_mode)
+static void mtl_ddi_cx0_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ enum icl_port_dpll_id port_dpll_id,
+ enum intel_dpll_id pll_id)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ struct icl_port_dpll *port_dpll;
+ struct intel_dpll *pll;
+ bool pll_active;
+
+ port_dpll = &crtc_state->icl_port_dplls[port_dpll_id];
+ pll = intel_get_dpll_by_id(display, pll_id);
+
+ if (drm_WARN_ON(display->drm, !pll))
+ return;
+
+ port_dpll->pll = pll;
+ pll_active = intel_dpll_get_hw_state(display, pll, &port_dpll->hw_state);
+ drm_WARN_ON(display->drm, !pll_active);
+
+ icl_set_active_port_dpll(crtc_state, port_dpll_id);
+
+ if (icl_ddi_tc_pll_is_tbt(crtc_state->intel_dpll))
crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder);
else
- crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->dpll_hw_state.cx0pll);
+ crtc_state->port_clock = intel_dpll_get_freq(display, crtc_state->intel_dpll,
+ &crtc_state->dpll_hw_state);
intel_ddi_get_config(encoder, crtc_state);
}
+/*
+ * Get the configuration for either a port using a C10 PHY PLL, or a port using a
+ * C20 PHY PLL in the cases of:
+ * - BMG port A/B
+ * - PTL port B eDP over TypeC PHY
+ */
+static void mtl_ddi_non_tc_phy_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(encoder);
+
+ mtl_ddi_cx0_get_config(encoder, crtc_state, ICL_PORT_DPLL_DEFAULT,
+ mtl_port_to_pll_id(display, encoder->port));
+}
+
+static void mtl_ddi_tc_phy_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_display *display = to_intel_display(encoder);
+
+ if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder)))
+ mtl_ddi_cx0_get_config(encoder, crtc_state, ICL_PORT_DPLL_DEFAULT,
+ DPLL_ID_ICL_TBTPLL);
+ else
+ mtl_ddi_cx0_get_config(encoder, crtc_state, ICL_PORT_DPLL_MG_PHY,
+ mtl_port_to_pll_id(display, encoder->port));
+}
+
static void dg2_ddi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state)
{
@@ -4305,11 +4358,6 @@ static void icl_ddi_combo_get_config(struct intel_encoder *encoder,
intel_ddi_get_config(encoder, crtc_state);
}
-static bool icl_ddi_tc_pll_is_tbt(const struct intel_dpll *pll)
-{
- return pll->info->id == DPLL_ID_ICL_TBTPLL;
-}
-
static enum icl_port_dpll_id
icl_ddi_tc_port_pll_type(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
@@ -5100,7 +5148,7 @@ static const char *intel_ddi_encoder_name(struct intel_display *display,
port_name(port - PORT_D_XELPD + PORT_D),
phy_name(phy));
} else if (DISPLAY_VER(display) >= 12) {
- enum tc_port tc_port = intel_port_to_tc(display, port);
+ enum tc_port tc_port = intel_tc_phy_port_to_tc(display, port);
seq_buf_printf(s, "DDI %s%c/PHY %s%c",
port >= PORT_TC1 ? "TC" : "",
@@ -5108,7 +5156,7 @@ static const char *intel_ddi_encoder_name(struct intel_display *display,
tc_port != TC_PORT_NONE ? "TC" : "",
tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
} else if (DISPLAY_VER(display) >= 11) {
- enum tc_port tc_port = intel_port_to_tc(display, port);
+ enum tc_port tc_port = intel_tc_phy_port_to_tc(display, port);
seq_buf_printf(s, "DDI %c%s/PHY %s%c",
port_name(port),
@@ -5252,10 +5300,13 @@ void intel_ddi_init(struct intel_display *display,
encoder->port_pll_type = intel_mtl_port_pll_type;
encoder->get_config = xe3plpd_ddi_get_config;
} else if (DISPLAY_VER(display) >= 14) {
- encoder->enable_clock = intel_mtl_pll_enable;
- encoder->disable_clock = intel_mtl_pll_disable;
- encoder->port_pll_type = intel_mtl_port_pll_type;
- encoder->get_config = mtl_ddi_get_config;
+ encoder->enable_clock = intel_mtl_pll_enable_clock;
+ encoder->disable_clock = intel_mtl_pll_disable_clock;
+ encoder->port_pll_type = icl_ddi_tc_port_pll_type;
+ if (intel_encoder_is_tc(encoder))
+ encoder->get_config = mtl_ddi_tc_phy_get_config;
+ else
+ encoder->get_config = mtl_ddi_non_tc_phy_get_config;
} else if (display->platform.dg2) {
encoder->enable_clock = intel_mpllb_enable;
encoder->disable_clock = intel_mpllb_disable;
@@ -5372,6 +5423,17 @@ void intel_ddi_init(struct intel_display *display,
goto err;
}
+ /*
+ * FIXME: We currently need to store dedicated_external because devdata
+ * does not live long enough for when intel_encoder_is_tc() is called on
+ * the unbind path. This needs to be fixed by making sure that the VBT
+ * data is kept long enough, so that
+ * intel_bios_encoder_is_dedicated_external() can be called directly
+ * from intel_encoder_is_tc().
+ */
+ if (intel_bios_encoder_is_dedicated_external(devdata))
+ dig_port->dedicated_external = true;
+
if (intel_encoder_is_tc(encoder)) {
bool is_legacy =
!intel_bios_encoder_supports_typec_usb(devdata) &&
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 095a319f8bc9..d5947cc9b94c 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -372,7 +372,7 @@ void assert_transcoder(struct intel_display *display,
{
bool cur_state;
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
/* we keep both pipes enabled on 830 */
if (display->platform.i830)
@@ -1810,7 +1810,17 @@ bool intel_phy_is_combo(struct intel_display *display, enum phy phy)
return false;
}
-/* Prefer intel_encoder_is_tc() */
+/*
+ * This function returns true if the DDI port respective to the PHY enumeration
+ * is a Type-C capable port.
+ *
+ * Depending on the VBT, the port might be configured
+ * as a "dedicated external" port, meaning that actual physical PHY is outside
+ * of the Type-C subsystem and, as such, not really a "Type-C PHY".
+ *
+ * Prefer intel_encoder_is_tc(), especially if you really need to know if we
+ * are dealing with Type-C connections.
+ */
bool intel_phy_is_tc(struct intel_display *display, enum phy phy)
{
/*
@@ -1859,17 +1869,32 @@ enum phy intel_port_to_phy(struct intel_display *display, enum port port)
}
/* Prefer intel_encoder_to_tc() */
+/*
+ * Return TC_PORT_1..I915_MAX_TC_PORTS for any TypeC DDI port. The function
+ * can be also called for TypeC DDI ports not connected to a TypeC PHY such as
+ * the PORT_TC1..4 ports on RKL/ADLS/BMG.
+ */
enum tc_port intel_port_to_tc(struct intel_display *display, enum port port)
{
- if (!intel_phy_is_tc(display, intel_port_to_phy(display, port)))
- return TC_PORT_NONE;
-
if (DISPLAY_VER(display) >= 12)
return TC_PORT_1 + port - PORT_TC1;
else
return TC_PORT_1 + port - PORT_C;
}
+/*
+ * Return TC_PORT_1..I915_MAX_TC_PORTS for TypeC DDI ports connected to a TypeC PHY.
+ * Note that on RKL, ADLS, BMG the PORT_TC1..4 ports are connected to a non-TypeC
+ * PHY, so on those platforms the function returns TC_PORT_NONE.
+ */
+enum tc_port intel_tc_phy_port_to_tc(struct intel_display *display, enum port port)
+{
+ if (!intel_phy_is_tc(display, intel_port_to_phy(display, port)))
+ return TC_PORT_NONE;
+
+ return intel_port_to_tc(display, port);
+}
+
enum phy intel_encoder_to_phy(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
@@ -1894,6 +1919,10 @@ bool intel_encoder_is_snps(struct intel_encoder *encoder)
bool intel_encoder_is_tc(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+ if (dig_port && dig_port->dedicated_external)
+ return false;
return intel_phy_is_tc(display, intel_encoder_to_phy(encoder));
}
@@ -1902,7 +1931,7 @@ enum tc_port intel_encoder_to_tc(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
- return intel_port_to_tc(display, encoder->port);
+ return intel_tc_phy_port_to_tc(display, encoder->port);
}
enum intel_display_power_domain
@@ -3020,7 +3049,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
struct intel_display *display = to_intel_display(crtc);
enum intel_display_power_domain power_domain;
enum transcoder cpu_transcoder = (enum transcoder)crtc->pipe;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret = false;
u32 tmp;
@@ -3364,7 +3393,7 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
struct intel_display *display = to_intel_display(crtc);
enum intel_display_power_domain power_domain;
enum transcoder cpu_transcoder = (enum transcoder)crtc->pipe;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret = false;
u32 tmp;
@@ -3454,12 +3483,11 @@ static bool transcoder_ddi_func_is_enabled(struct intel_display *display,
enum transcoder cpu_transcoder)
{
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
u32 tmp = 0;
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
- with_intel_display_power_if_enabled(display, power_domain, wakeref)
+ with_intel_display_power_if_enabled(display, power_domain)
tmp = intel_de_read(display,
TRANS_DDI_FUNC_CTL(display, cpu_transcoder));
@@ -3481,10 +3509,9 @@ static void enabled_uncompressed_joiner_pipes(struct intel_display *display,
joiner_pipes(display)) {
enum intel_display_power_domain power_domain;
enum pipe pipe = crtc->pipe;
- intel_wakeref_t wakeref;
power_domain = POWER_DOMAIN_PIPE(pipe);
- with_intel_display_power_if_enabled(display, power_domain, wakeref) {
+ with_intel_display_power_if_enabled(display, power_domain) {
u32 tmp = intel_de_read(display, ICL_PIPE_DSS_CTL1(pipe));
if (tmp & UNCOMPRESSED_JOINER_PRIMARY)
@@ -3510,10 +3537,9 @@ static void enabled_bigjoiner_pipes(struct intel_display *display,
joiner_pipes(display)) {
enum intel_display_power_domain power_domain;
enum pipe pipe = crtc->pipe;
- intel_wakeref_t wakeref;
power_domain = intel_dsc_power_domain(crtc, (enum transcoder)pipe);
- with_intel_display_power_if_enabled(display, power_domain, wakeref) {
+ with_intel_display_power_if_enabled(display, power_domain) {
u32 tmp = intel_de_read(display, ICL_PIPE_DSS_CTL1(pipe));
if (!(tmp & BIG_JOINER_ENABLE))
@@ -3580,10 +3606,9 @@ static void enabled_ultrajoiner_pipes(struct intel_display *display,
joiner_pipes(display)) {
enum intel_display_power_domain power_domain;
enum pipe pipe = crtc->pipe;
- intel_wakeref_t wakeref;
power_domain = intel_dsc_power_domain(crtc, (enum transcoder)pipe);
- with_intel_display_power_if_enabled(display, power_domain, wakeref) {
+ with_intel_display_power_if_enabled(display, power_domain) {
u32 tmp = intel_de_read(display, ICL_PIPE_DSS_CTL1(pipe));
if (!(tmp & ULTRA_JOINER_ENABLE))
@@ -3741,12 +3766,11 @@ static u8 hsw_enabled_transcoders(struct intel_crtc *crtc)
for_each_cpu_transcoder_masked(display, cpu_transcoder,
panel_transcoder_mask) {
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
enum pipe trans_pipe;
u32 tmp = 0;
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
- with_intel_display_power_if_enabled(display, power_domain, wakeref)
+ with_intel_display_power_if_enabled(display, power_domain)
tmp = intel_de_read(display,
TRANS_DDI_FUNC_CTL(display, cpu_transcoder));
@@ -4977,24 +5001,6 @@ pipe_config_pll_mismatch(struct drm_printer *p, bool fastset,
intel_dpll_dump_hw_state(display, p, b);
}
-static void
-pipe_config_cx0pll_mismatch(struct drm_printer *p, bool fastset,
- const struct intel_crtc *crtc,
- const char *name,
- const struct intel_cx0pll_state *a,
- const struct intel_cx0pll_state *b)
-{
- struct intel_display *display = to_intel_display(crtc);
- char *chipname = a->use_c10 ? "C10" : "C20";
-
- pipe_config_mismatch(p, fastset, crtc, name, chipname);
-
- drm_printf(p, "expected:\n");
- intel_cx0pll_dump_hw_state(display, a);
- drm_printf(p, "found:\n");
- intel_cx0pll_dump_hw_state(display, b);
-}
-
static bool allow_vblank_delay_fastset(const struct intel_crtc_state *old_crtc_state)
{
struct intel_display *display = to_intel_display(old_crtc_state);
@@ -5146,16 +5152,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
} \
} while (0)
-#define PIPE_CONF_CHECK_PLL_CX0(name) do { \
- if (!intel_cx0pll_compare_hw_state(&current_config->name, \
- &pipe_config->name)) { \
- pipe_config_cx0pll_mismatch(&p, fastset, crtc, __stringify(name), \
- &current_config->name, \
- &pipe_config->name); \
- ret = false; \
- } \
-} while (0)
-
#define PIPE_CONF_CHECK_PLL_LT(name) do { \
if (!intel_lt_phy_pll_compare_hw_state(&current_config->name, \
&pipe_config->name)) { \
@@ -5395,8 +5391,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
/* FIXME convert MTL+ platforms over to dpll_mgr */
if (HAS_LT_PHY(display))
PIPE_CONF_CHECK_PLL_LT(dpll_hw_state.ltpll);
- else if (DISPLAY_VER(display) >= 14)
- PIPE_CONF_CHECK_PLL_CX0(dpll_hw_state.cx0pll);
PIPE_CONF_CHECK_X(dsi_pll.ctrl);
PIPE_CONF_CHECK_X(dsi_pll.div);
@@ -6032,14 +6026,6 @@ static int intel_async_flip_check_uapi(struct intel_atomic_state *state,
return -EINVAL;
}
- /* FIXME: selective fetch should be disabled for async flips */
- if (new_crtc_state->enable_psr2_sel_fetch) {
- drm_dbg_kms(display->drm,
- "[CRTC:%d:%s] async flip disallowed with PSR2 selective fetch\n",
- crtc->base.base.id, crtc->base.name);
- return -EINVAL;
- }
-
for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
new_plane_state, i) {
if (plane->pipe != crtc->pipe)
@@ -6130,7 +6116,7 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in
if (!plane->async_flip)
continue;
- if (!intel_plane_can_async_flip(plane, new_plane_state->hw.fb->format->format,
+ if (!intel_plane_can_async_flip(plane, new_plane_state->hw.fb->format,
new_plane_state->hw.fb->modifier)) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] pixel format %p4cc / modifier 0x%llx does not support async flip\n",
@@ -7399,7 +7385,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
struct intel_crtc_state *new_crtc_state, *old_crtc_state;
struct intel_crtc *crtc;
struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {};
- intel_wakeref_t wakeref = NULL;
+ struct ref_tracker *wakeref = NULL;
int i;
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index bcc6ccb69d2b..f8e6e4e82722 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -451,6 +451,7 @@ bool intel_phy_is_combo(struct intel_display *display, enum phy phy);
bool intel_phy_is_tc(struct intel_display *display, enum phy phy);
bool intel_phy_is_snps(struct intel_display *display, enum phy phy);
enum tc_port intel_port_to_tc(struct intel_display *display, enum port port);
+enum tc_port intel_tc_phy_port_to_tc(struct intel_display *display, enum port port);
enum phy intel_encoder_to_phy(struct intel_encoder *encoder);
bool intel_encoder_is_combo(struct intel_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 9b8414b77c15..d708d322aa85 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -386,7 +386,7 @@ struct intel_display {
struct {
struct intel_dmc *dmc;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
} dmc;
struct {
@@ -395,6 +395,21 @@ struct intel_display {
} dsi;
struct {
+ const struct dram_info *info;
+ } dram;
+
+ struct {
+ struct intel_fbc *instances[I915_MAX_FBCS];
+
+ /* xe3p_lpd+: FBC instance utilizing the system cache */
+ struct sys_cache_cfg {
+ /* Protect concurrecnt access to system cache configuration */
+ struct mutex lock;
+ enum intel_fbc_id id;
+ } sys_cache;
+ } fbc;
+
+ struct {
/* list of fbdev register on this device */
struct intel_fbdev *fbdev;
} fbdev;
@@ -611,7 +626,6 @@ struct intel_display {
struct drm_dp_tunnel_mgr *dp_tunnel_mgr;
struct intel_audio audio;
struct intel_dpll_global dpll;
- struct intel_fbc *fbc[I915_MAX_FBCS];
struct intel_frontbuffer_tracking fb_tracking;
struct intel_hotplug hotplug;
struct intel_opregion *opregion;
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 9bbfdae8d024..aba13e8a9051 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -86,7 +86,7 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused)
static int i915_sr_status(struct seq_file *m, void *unused)
{
struct intel_display *display = node_to_intel_display(m->private);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool sr_enabled = false;
wakeref = intel_display_power_get(display, POWER_DOMAIN_INIT);
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c
index 1170afaa8680..471f236c9ddf 100644
--- a/drivers/gpu/drm/i915/display/intel_display_device.c
+++ b/drivers/gpu/drm/i915/display/intel_display_device.c
@@ -1420,6 +1420,10 @@ static const struct platform_desc ptl_desc = {
}
};
+static const struct platform_desc nvl_desc = {
+ PLATFORM(novalake),
+};
+
__diag_pop();
/*
@@ -1495,6 +1499,7 @@ static const struct {
INTEL_BMG_IDS(INTEL_DISPLAY_DEVICE, &bmg_desc),
INTEL_PTL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc),
INTEL_WCL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc),
+ INTEL_NVLS_IDS(INTEL_DISPLAY_DEVICE, &nvl_desc),
};
static const struct {
diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h
index b559ef43d547..50b2e9ae2c18 100644
--- a/drivers/gpu/drm/i915/display/intel_display_device.h
+++ b/drivers/gpu/drm/i915/display/intel_display_device.h
@@ -103,7 +103,9 @@ struct pci_dev;
func(battlemage) \
/* Display ver 30 (based on GMD ID) */ \
func(pantherlake) \
- func(pantherlake_wildcatlake)
+ func(pantherlake_wildcatlake) \
+ /* Display ver 35 (based on GMD ID) */ \
+ func(novalake)
#define __MEMBER(name) unsigned long name:1;
@@ -147,7 +149,7 @@ struct intel_display_platforms {
#define HAS_4TILE(__display) ((__display)->platform.dg2 || DISPLAY_VER(__display) >= 14)
#define HAS_ASYNC_FLIPS(__display) (DISPLAY_VER(__display) >= 5)
#define HAS_AS_SDP(__display) (DISPLAY_VER(__display) >= 13)
-#define HAS_AUX_CCS(__display) (IS_DISPLAY_VER(__display, 9, 12) || (__display)->platform.alderlake_p || (__display)->platform.meteorlake)
+#define HAS_AUX_DIST(__display) (IS_DISPLAY_VER(__display, 9, 12) || (__display)->platform.alderlake_p || (__display)->platform.meteorlake)
#define HAS_BIGJOINER(__display) (DISPLAY_VER(__display) >= 11 && HAS_DSC(__display))
#define HAS_CASF(__display) (DISPLAY_VER(__display) >= 20)
#define HAS_CDCLK_CRAWL(__display) (DISPLAY_INFO(__display)->has_cdclk_crawl)
@@ -173,6 +175,7 @@ struct intel_display_platforms {
#define HAS_DSC_MST(__display) (DISPLAY_VER(__display) >= 12 && HAS_DSC(__display))
#define HAS_FBC(__display) (DISPLAY_RUNTIME_INFO(__display)->fbc_mask != 0)
#define HAS_FBC_DIRTY_RECT(__display) (DISPLAY_VER(__display) >= 30)
+#define HAS_FBC_SYS_CACHE(__display) (DISPLAY_VER(__display) >= 35 && !(__display)->platform.dgfx)
#define HAS_FPGA_DBG_UNCLAIMED(__display) (DISPLAY_INFO(__display)->has_fpga_dbg)
#define HAS_FW_BLC(__display) (DISPLAY_VER(__display) >= 3)
#define HAS_GMBUS_BURST_READ(__display) (DISPLAY_VER(__display) >= 10 || (__display)->platform.kabylake)
@@ -185,6 +188,7 @@ struct intel_display_platforms {
#define HAS_IPS(__display) ((__display)->platform.haswell_ult || (__display)->platform.broadwell)
#define HAS_LRR(__display) (DISPLAY_VER(__display) >= 12)
#define HAS_LSPCON(__display) (IS_DISPLAY_VER(__display, 9, 10))
+#define HAS_LT_PHY(__display) ((__display)->platform.novalake)
#define HAS_MBUS_JOINING(__display) ((__display)->platform.alderlake_p || DISPLAY_VER(__display) >= 14)
#define HAS_MSO(__display) (DISPLAY_VER(__display) >= 12)
#define HAS_OVERLAY(__display) (DISPLAY_INFO(__display)->has_overlay)
@@ -197,6 +201,7 @@ struct intel_display_platforms {
#define HAS_TRANSCODER(__display, trans) ((DISPLAY_RUNTIME_INFO(__display)->cpu_transcoder_mask & \
BIT(trans)) != 0)
#define HAS_UNCOMPRESSED_JOINER(__display) (DISPLAY_VER(__display) >= 13)
+#define HAS_UNDERRUN_DBG_INFO(__display) (DISPLAY_VER(__display) >= 35)
#define HAS_ULTRAJOINER(__display) (((__display)->platform.dgfx && \
DISPLAY_VER(__display) == 14) && HAS_DSC(__display))
#define HAS_VRR(__display) (DISPLAY_VER(__display) >= 11)
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 7e000ba3e08b..e1d29aea0ddc 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -199,12 +199,8 @@ void intel_display_driver_early_probe(struct intel_display *display)
/* part #1: call before irq install */
int intel_display_driver_probe_noirq(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
int ret;
- if (i915_inject_probe_failure(i915))
- return -ENODEV;
-
if (HAS_DISPLAY(display)) {
ret = drm_vblank_init(display->drm,
INTEL_NUM_PIPES(display));
@@ -317,6 +313,7 @@ cleanup_bios:
return ret;
}
+ALLOW_ERROR_INJECTION(intel_display_driver_probe_noirq, ERRNO);
static void set_display_access(struct intel_display *display,
bool any_task_allowed,
@@ -452,7 +449,6 @@ bool intel_display_driver_check_access(struct intel_display *display)
/* part #2: call after irq install, but before gem init */
int intel_display_driver_probe_nogem(struct intel_display *display)
{
- enum pipe pipe;
int ret;
if (!HAS_DISPLAY(display))
@@ -466,15 +462,9 @@ int intel_display_driver_probe_nogem(struct intel_display *display)
intel_gmbus_setup(display);
- drm_dbg_kms(display->drm, "%d display pipe%s available.\n",
- INTEL_NUM_PIPES(display),
- INTEL_NUM_PIPES(display) > 1 ? "s" : "");
-
- for_each_pipe(display, pipe) {
- ret = intel_crtc_init(display, pipe);
- if (ret)
- goto err_mode_config;
- }
+ ret = intel_crtc_init(display);
+ if (ret)
+ goto err_mode_config;
intel_plane_possible_crtcs_init(display);
intel_dpll_init(display);
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index 43b27deb4a26..9adeebb376b1 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -6,8 +6,6 @@
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
-#include "i915_drv.h"
-#include "i915_irq.h"
#include "i915_reg.h"
#include "icl_dsi_regs.h"
#include "intel_crtc.h"
@@ -19,57 +17,83 @@
#include "intel_display_trace.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
-#include "intel_dmc_wl.h"
#include "intel_dp_aux.h"
#include "intel_dsb.h"
#include "intel_fdi_regs.h"
#include "intel_fifo_underrun.h"
#include "intel_gmbus.h"
#include "intel_hotplug_irq.h"
+#include "intel_parent.h"
#include "intel_pipe_crc_regs.h"
#include "intel_plane.h"
#include "intel_pmdemand.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
-#include "intel_uncore.h"
-static void
-intel_display_irq_regs_init(struct intel_display *display, struct i915_irq_regs regs,
- u32 imr_val, u32 ier_val)
+static void irq_reset(struct intel_display *display, struct i915_irq_regs regs)
{
- intel_dmc_wl_get(display, regs.imr);
- intel_dmc_wl_get(display, regs.ier);
- intel_dmc_wl_get(display, regs.iir);
+ intel_de_write(display, regs.imr, 0xffffffff);
+ intel_de_posting_read(display, regs.imr);
- gen2_irq_init(to_intel_uncore(display->drm), regs, imr_val, ier_val);
+ intel_de_write(display, regs.ier, 0);
- intel_dmc_wl_put(display, regs.iir);
- intel_dmc_wl_put(display, regs.ier);
- intel_dmc_wl_put(display, regs.imr);
+ /* IIR can theoretically queue up two events. Be paranoid. */
+ intel_de_write(display, regs.iir, 0xffffffff);
+ intel_de_posting_read(display, regs.iir);
+ intel_de_write(display, regs.iir, 0xffffffff);
+ intel_de_posting_read(display, regs.iir);
}
-static void
-intel_display_irq_regs_reset(struct intel_display *display, struct i915_irq_regs regs)
+/*
+ * We should clear IMR at preinstall/uninstall, and just check at postinstall.
+ */
+static void assert_iir_is_zero(struct intel_display *display, i915_reg_t reg)
{
- intel_dmc_wl_get(display, regs.imr);
- intel_dmc_wl_get(display, regs.ier);
- intel_dmc_wl_get(display, regs.iir);
+ u32 val = intel_de_read(display, reg);
- gen2_irq_reset(to_intel_uncore(display->drm), regs);
+ if (val == 0)
+ return;
- intel_dmc_wl_put(display, regs.iir);
- intel_dmc_wl_put(display, regs.ier);
- intel_dmc_wl_put(display, regs.imr);
+ drm_WARN(display->drm, 1,
+ "Interrupt register 0x%x is not zero: 0x%08x\n",
+ i915_mmio_reg_offset(reg), val);
+ intel_de_write(display, reg, 0xffffffff);
+ intel_de_posting_read(display, reg);
+ intel_de_write(display, reg, 0xffffffff);
+ intel_de_posting_read(display, reg);
}
-static void
-intel_display_irq_regs_assert_irr_is_zero(struct intel_display *display, i915_reg_t reg)
+static void irq_init(struct intel_display *display, struct i915_irq_regs regs,
+ u32 imr_val, u32 ier_val)
{
- intel_dmc_wl_get(display, reg);
+ assert_iir_is_zero(display, regs.iir);
+
+ intel_de_write(display, regs.ier, ier_val);
+ intel_de_write(display, regs.imr, imr_val);
+ intel_de_posting_read(display, regs.imr);
+}
- gen2_assert_iir_is_zero(to_intel_uncore(display->drm), reg);
+static void error_reset(struct intel_display *display, struct i915_error_regs regs)
+{
+ intel_de_write(display, regs.emr, 0xffffffff);
+ intel_de_posting_read(display, regs.emr);
- intel_dmc_wl_put(display, reg);
+ intel_de_write(display, regs.eir, 0xffffffff);
+ intel_de_posting_read(display, regs.eir);
+ intel_de_write(display, regs.eir, 0xffffffff);
+ intel_de_posting_read(display, regs.eir);
+}
+
+static void error_init(struct intel_display *display, struct i915_error_regs regs,
+ u32 emr_val)
+{
+ intel_de_write(display, regs.eir, 0xffffffff);
+ intel_de_posting_read(display, regs.eir);
+ intel_de_write(display, regs.eir, 0xffffffff);
+ intel_de_posting_read(display, regs.eir);
+
+ intel_de_write(display, regs.emr, emr_val);
+ intel_de_posting_read(display, regs.emr);
}
struct pipe_fault_handler {
@@ -135,7 +159,6 @@ intel_handle_vblank(struct intel_display *display, enum pipe pipe)
void ilk_update_display_irq(struct intel_display *display,
u32 interrupt_mask, u32 enabled_irq_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 new_val;
lockdep_assert_held(&display->irq.lock);
@@ -146,7 +169,7 @@ void ilk_update_display_irq(struct intel_display *display,
new_val |= (~enabled_irq_mask & interrupt_mask);
if (new_val != display->irq.ilk_de_imr_mask &&
- !drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv))) {
+ !drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display))) {
display->irq.ilk_de_imr_mask = new_val;
intel_de_write(display, DEIMR, display->irq.ilk_de_imr_mask);
intel_de_posting_read(display, DEIMR);
@@ -172,7 +195,6 @@ void ilk_disable_display_irq(struct intel_display *display, u32 bits)
void bdw_update_port_irq(struct intel_display *display,
u32 interrupt_mask, u32 enabled_irq_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 new_val;
u32 old_val;
@@ -180,7 +202,7 @@ void bdw_update_port_irq(struct intel_display *display,
drm_WARN_ON(display->drm, enabled_irq_mask & ~interrupt_mask);
- if (drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv)))
+ if (drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display)))
return;
old_val = intel_de_read(display, GEN8_DE_PORT_IMR);
@@ -206,14 +228,13 @@ static void bdw_update_pipe_irq(struct intel_display *display,
enum pipe pipe, u32 interrupt_mask,
u32 enabled_irq_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 new_val;
lockdep_assert_held(&display->irq.lock);
drm_WARN_ON(display->drm, enabled_irq_mask & ~interrupt_mask);
- if (drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv)))
+ if (drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display)))
return;
new_val = display->irq.de_pipe_imr_mask[pipe];
@@ -249,7 +270,6 @@ void ibx_display_interrupt_update(struct intel_display *display,
u32 interrupt_mask,
u32 enabled_irq_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 sdeimr = intel_de_read(display, SDEIMR);
sdeimr &= ~interrupt_mask;
@@ -259,7 +279,7 @@ void ibx_display_interrupt_update(struct intel_display *display,
lockdep_assert_held(&display->irq.lock);
- if (drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv)))
+ if (drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display)))
return;
intel_de_write(display, SDEIMR, sdeimr);
@@ -323,7 +343,6 @@ out:
void i915_enable_pipestat(struct intel_display *display,
enum pipe pipe, u32 status_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
i915_reg_t reg = PIPESTAT(display, pipe);
u32 enable_mask;
@@ -332,7 +351,7 @@ void i915_enable_pipestat(struct intel_display *display,
pipe_name(pipe), status_mask);
lockdep_assert_held(&display->irq.lock);
- drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv));
+ drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display));
if ((display->irq.pipestat_irq_mask[pipe] & status_mask) == status_mask)
return;
@@ -347,7 +366,6 @@ void i915_enable_pipestat(struct intel_display *display,
void i915_disable_pipestat(struct intel_display *display,
enum pipe pipe, u32 status_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
i915_reg_t reg = PIPESTAT(display, pipe);
u32 enable_mask;
@@ -356,7 +374,7 @@ void i915_disable_pipestat(struct intel_display *display,
pipe_name(pipe), status_mask);
lockdep_assert_held(&display->irq.lock);
- drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv));
+ drm_WARN_ON(display->drm, !intel_parent_irq_enabled(display));
if ((display->irq.pipestat_irq_mask[pipe] & status_mask) == 0)
return;
@@ -1918,15 +1936,14 @@ static void _vlv_display_irq_reset(struct intel_display *display)
else
intel_de_write(display, DPINVGTT, DPINVGTT_STATUS_MASK_VLV);
- gen2_error_reset(to_intel_uncore(display->drm),
- VLV_ERROR_REGS);
+ error_reset(display, VLV_ERROR_REGS);
i915_hotplug_interrupt_update_locked(display, 0xffffffff, 0);
intel_de_rmw(display, PORT_HOTPLUG_STAT(display), 0, 0);
i9xx_pipestat_irq_reset(display);
- intel_display_irq_regs_reset(display, VLV_IRQ_REGS);
+ irq_reset(display, VLV_IRQ_REGS);
display->irq.vlv_imr_mask = ~0u;
}
@@ -2014,8 +2031,7 @@ static void _vlv_display_irq_postinstall(struct intel_display *display)
DPINVGTT_STATUS_MASK_VLV |
DPINVGTT_EN_MASK_VLV);
- gen2_error_init(to_intel_uncore(display->drm),
- VLV_ERROR_REGS, ~vlv_error_mask());
+ error_init(display, VLV_ERROR_REGS, ~vlv_error_mask());
pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
@@ -2038,7 +2054,7 @@ static void _vlv_display_irq_postinstall(struct intel_display *display)
display->irq.vlv_imr_mask = ~enable_mask;
- intel_display_irq_regs_init(display, VLV_IRQ_REGS, display->irq.vlv_imr_mask, enable_mask);
+ irq_init(display, VLV_IRQ_REGS, display->irq.vlv_imr_mask, enable_mask);
}
void vlv_display_irq_postinstall(struct intel_display *display)
@@ -2054,7 +2070,7 @@ static void ibx_display_irq_reset(struct intel_display *display)
if (HAS_PCH_NOP(display))
return;
- gen2_irq_reset(to_intel_uncore(display->drm), SDE_IRQ_REGS);
+ irq_reset(display, SDE_IRQ_REGS);
if (HAS_PCH_CPT(display) || HAS_PCH_LPT(display))
intel_de_write(display, SERR_INT, 0xffffffff);
@@ -2062,9 +2078,7 @@ static void ibx_display_irq_reset(struct intel_display *display)
void ilk_display_irq_reset(struct intel_display *display)
{
- struct intel_uncore *uncore = to_intel_uncore(display->drm);
-
- gen2_irq_reset(uncore, DE_IRQ_REGS);
+ irq_reset(display, DE_IRQ_REGS);
display->irq.ilk_de_imr_mask = ~0u;
if (DISPLAY_VER(display) == 7)
@@ -2091,10 +2105,10 @@ void gen8_display_irq_reset(struct intel_display *display)
for_each_pipe(display, pipe)
if (intel_display_power_is_enabled(display,
POWER_DOMAIN_PIPE(pipe)))
- intel_display_irq_regs_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
+ irq_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
- intel_display_irq_regs_reset(display, GEN8_DE_PORT_IRQ_REGS);
- intel_display_irq_regs_reset(display, GEN8_DE_MISC_IRQ_REGS);
+ irq_reset(display, GEN8_DE_PORT_IRQ_REGS);
+ irq_reset(display, GEN8_DE_MISC_IRQ_REGS);
if (HAS_PCH_SPLIT(display))
ibx_display_irq_reset(display);
@@ -2136,39 +2150,38 @@ void gen11_display_irq_reset(struct intel_display *display)
for_each_pipe(display, pipe)
if (intel_display_power_is_enabled(display,
POWER_DOMAIN_PIPE(pipe)))
- intel_display_irq_regs_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
+ irq_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
- intel_display_irq_regs_reset(display, GEN8_DE_PORT_IRQ_REGS);
- intel_display_irq_regs_reset(display, GEN8_DE_MISC_IRQ_REGS);
+ irq_reset(display, GEN8_DE_PORT_IRQ_REGS);
+ irq_reset(display, GEN8_DE_MISC_IRQ_REGS);
if (DISPLAY_VER(display) >= 14)
- intel_display_irq_regs_reset(display, PICAINTERRUPT_IRQ_REGS);
+ irq_reset(display, PICAINTERRUPT_IRQ_REGS);
else
- intel_display_irq_regs_reset(display, GEN11_DE_HPD_IRQ_REGS);
+ irq_reset(display, GEN11_DE_HPD_IRQ_REGS);
if (INTEL_PCH_TYPE(display) >= PCH_ICP)
- intel_display_irq_regs_reset(display, SDE_IRQ_REGS);
+ irq_reset(display, SDE_IRQ_REGS);
}
void gen8_irq_power_well_post_enable(struct intel_display *display,
u8 pipe_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN |
gen8_de_pipe_flip_done_mask(display);
enum pipe pipe;
spin_lock_irq(&display->irq.lock);
- if (!intel_irqs_enabled(dev_priv)) {
+ if (!intel_parent_irq_enabled(display)) {
spin_unlock_irq(&display->irq.lock);
return;
}
for_each_pipe_masked(display, pipe, pipe_mask)
- intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe),
- display->irq.de_pipe_imr_mask[pipe],
- ~display->irq.de_pipe_imr_mask[pipe] | extra_ier);
+ irq_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe),
+ display->irq.de_pipe_imr_mask[pipe],
+ ~display->irq.de_pipe_imr_mask[pipe] | extra_ier);
spin_unlock_irq(&display->irq.lock);
}
@@ -2176,23 +2189,22 @@ void gen8_irq_power_well_post_enable(struct intel_display *display,
void gen8_irq_power_well_pre_disable(struct intel_display *display,
u8 pipe_mask)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
enum pipe pipe;
spin_lock_irq(&display->irq.lock);
- if (!intel_irqs_enabled(dev_priv)) {
+ if (!intel_parent_irq_enabled(display)) {
spin_unlock_irq(&display->irq.lock);
return;
}
for_each_pipe_masked(display, pipe, pipe_mask)
- intel_display_irq_regs_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
+ irq_reset(display, GEN8_DE_PIPE_IRQ_REGS(pipe));
spin_unlock_irq(&display->irq.lock);
/* make sure we're done processing display irqs */
- intel_synchronize_irq(dev_priv);
+ intel_parent_irq_synchronize(display);
}
/*
@@ -2220,13 +2232,11 @@ static void ibx_irq_postinstall(struct intel_display *display)
else
mask = SDE_GMBUS_CPT;
- intel_display_irq_regs_init(display, SDE_IRQ_REGS, ~mask, 0xffffffff);
+ irq_init(display, SDE_IRQ_REGS, ~mask, 0xffffffff);
}
void valleyview_enable_display_irqs(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
-
spin_lock_irq(&display->irq.lock);
if (display->irq.vlv_display_irqs_enabled)
@@ -2234,7 +2244,7 @@ void valleyview_enable_display_irqs(struct intel_display *display)
display->irq.vlv_display_irqs_enabled = true;
- if (intel_irqs_enabled(dev_priv)) {
+ if (intel_parent_irq_enabled(display)) {
_vlv_display_irq_reset(display);
_vlv_display_irq_postinstall(display);
}
@@ -2245,8 +2255,6 @@ out:
void valleyview_disable_display_irqs(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
-
spin_lock_irq(&display->irq.lock);
if (!display->irq.vlv_display_irqs_enabled)
@@ -2254,7 +2262,7 @@ void valleyview_disable_display_irqs(struct intel_display *display)
display->irq.vlv_display_irqs_enabled = false;
- if (intel_irqs_enabled(dev_priv))
+ if (intel_parent_irq_enabled(display))
_vlv_display_irq_reset(display);
out:
spin_unlock_irq(&display->irq.lock);
@@ -2286,7 +2294,7 @@ void ilk_de_irq_postinstall(struct intel_display *display)
}
if (display->platform.haswell) {
- intel_display_irq_regs_assert_irr_is_zero(display, EDP_PSR_IIR);
+ assert_iir_is_zero(display, EDP_PSR_IIR);
display_mask |= DE_EDP_PSR_INT_HSW;
}
@@ -2297,8 +2305,8 @@ void ilk_de_irq_postinstall(struct intel_display *display)
ibx_irq_postinstall(display);
- intel_display_irq_regs_init(display, DE_IRQ_REGS, display->irq.ilk_de_imr_mask,
- display_mask | extra_mask);
+ irq_init(display, DE_IRQ_REGS, display->irq.ilk_de_imr_mask,
+ display_mask | extra_mask);
}
static void mtp_irq_postinstall(struct intel_display *display);
@@ -2374,11 +2382,10 @@ void gen8_de_irq_postinstall(struct intel_display *display)
if (!intel_display_power_is_enabled(display, domain))
continue;
- intel_display_irq_regs_assert_irr_is_zero(display,
- TRANS_PSR_IIR(display, trans));
+ assert_iir_is_zero(display, TRANS_PSR_IIR(display, trans));
}
} else {
- intel_display_irq_regs_assert_irr_is_zero(display, EDP_PSR_IIR);
+ assert_iir_is_zero(display, EDP_PSR_IIR);
}
for_each_pipe(display, pipe) {
@@ -2386,44 +2393,50 @@ void gen8_de_irq_postinstall(struct intel_display *display)
if (intel_display_power_is_enabled(display,
POWER_DOMAIN_PIPE(pipe)))
- intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe),
- display->irq.de_pipe_imr_mask[pipe],
- de_pipe_enables);
+ irq_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe),
+ display->irq.de_pipe_imr_mask[pipe],
+ de_pipe_enables);
}
- intel_display_irq_regs_init(display, GEN8_DE_PORT_IRQ_REGS, ~de_port_masked,
- de_port_enables);
- intel_display_irq_regs_init(display, GEN8_DE_MISC_IRQ_REGS, ~de_misc_masked,
- de_misc_masked);
+ irq_init(display, GEN8_DE_PORT_IRQ_REGS, ~de_port_masked, de_port_enables);
+ irq_init(display, GEN8_DE_MISC_IRQ_REGS, ~de_misc_masked, de_misc_masked);
if (IS_DISPLAY_VER(display, 11, 13)) {
u32 de_hpd_masked = 0;
u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK |
GEN11_DE_TBT_HOTPLUG_MASK;
- intel_display_irq_regs_init(display, GEN11_DE_HPD_IRQ_REGS, ~de_hpd_masked,
- de_hpd_enables);
+ irq_init(display, GEN11_DE_HPD_IRQ_REGS, ~de_hpd_masked, de_hpd_enables);
}
}
+u32 xelpdp_pica_aux_mask(struct intel_display *display)
+{
+ u32 mask = XELPDP_AUX_TC_MASK;
+
+ if (DISPLAY_VER(display) >= 20)
+ mask |= XE2LPD_AUX_DDI_MASK;
+
+ return mask;
+}
+
static void mtp_irq_postinstall(struct intel_display *display)
{
u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT;
- u32 de_hpd_mask = XELPDP_AUX_TC_MASK;
+ u32 de_hpd_mask = xelpdp_pica_aux_mask(display);
u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK |
XELPDP_TBT_HOTPLUG_MASK;
- intel_display_irq_regs_init(display, PICAINTERRUPT_IRQ_REGS, ~de_hpd_mask,
- de_hpd_enables);
+ irq_init(display, PICAINTERRUPT_IRQ_REGS, ~de_hpd_mask, de_hpd_enables);
- intel_display_irq_regs_init(display, SDE_IRQ_REGS, ~sde_mask, 0xffffffff);
+ irq_init(display, SDE_IRQ_REGS, ~sde_mask, 0xffffffff);
}
static void icp_irq_postinstall(struct intel_display *display)
{
u32 mask = SDE_GMBUS_ICP;
- intel_display_irq_regs_init(display, SDE_IRQ_REGS, ~mask, 0xffffffff);
+ irq_init(display, SDE_IRQ_REGS, ~mask, 0xffffffff);
}
void gen11_de_irq_postinstall(struct intel_display *display)
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h
index 84acd31948cf..b25d180254d7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.h
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.h
@@ -16,6 +16,8 @@ struct drm_printer;
struct intel_display;
struct intel_display_irq_snapshot;
+u32 xelpdp_pica_aux_mask(struct intel_display *display);
+
void valleyview_enable_display_irqs(struct intel_display *display);
void valleyview_disable_display_irqs(struct intel_display *display);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 2a4cc1dcc293..47042a4c3a30 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -8,10 +8,7 @@
#include <drm/drm_print.h>
-#include "soc/intel_dram.h"
-
#include "i915_drv.h"
-#include "i915_irq.h"
#include "i915_reg.h"
#include "intel_backlight_regs.h"
#include "intel_cdclk.h"
@@ -26,7 +23,9 @@
#include "intel_display_types.h"
#include "intel_display_utils.h"
#include "intel_dmc.h"
+#include "intel_dram.h"
#include "intel_mchbar_regs.h"
+#include "intel_parent.h"
#include "intel_pch_refclk.h"
#include "intel_pcode.h"
#include "intel_pmdemand.h"
@@ -545,8 +544,8 @@ __intel_display_power_get_domain(struct intel_display *display,
* Any power domain reference obtained by this function must have a symmetric
* call to intel_display_power_put() to release the reference again.
*/
-intel_wakeref_t intel_display_power_get(struct intel_display *display,
- enum intel_display_power_domain domain)
+struct ref_tracker *intel_display_power_get(struct intel_display *display,
+ enum intel_display_power_domain domain)
{
struct i915_power_domains *power_domains = &display->power.domains;
struct ref_tracker *wakeref;
@@ -572,7 +571,7 @@ intel_wakeref_t intel_display_power_get(struct intel_display *display,
* Any power domain reference obtained by this function must have a symmetric
* call to intel_display_power_put() to release the reference again.
*/
-intel_wakeref_t
+struct ref_tracker *
intel_display_power_get_if_enabled(struct intel_display *display,
enum intel_display_power_domain domain)
{
@@ -639,7 +638,7 @@ static void __intel_display_power_put(struct intel_display *display,
static void
queue_async_put_domains_work(struct i915_power_domains *power_domains,
- intel_wakeref_t wakeref,
+ struct ref_tracker *wakeref,
int delay_ms)
{
struct intel_display *display = container_of(power_domains,
@@ -741,7 +740,7 @@ out_verify:
*/
void __intel_display_power_put_async(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref,
+ struct ref_tracker *wakeref,
int delay_ms)
{
struct i915_power_domains *power_domains = &display->power.domains;
@@ -800,7 +799,7 @@ void intel_display_power_flush_work(struct intel_display *display)
{
struct i915_power_domains *power_domains = &display->power.domains;
struct intel_power_domain_mask async_put_mask;
- intel_wakeref_t work_wakeref;
+ struct ref_tracker *work_wakeref;
mutex_lock(&power_domains->lock);
@@ -854,7 +853,7 @@ intel_display_power_flush_work_sync(struct intel_display *display)
*/
void intel_display_power_put(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref)
+ struct ref_tracker *wakeref)
{
__intel_display_power_put(display, domain);
intel_display_rpm_put(display, wakeref);
@@ -886,7 +885,7 @@ intel_display_power_get_in_set(struct intel_display *display,
struct intel_display_power_domain_set *power_domain_set,
enum intel_display_power_domain domain)
{
- intel_wakeref_t __maybe_unused wf;
+ struct ref_tracker *__maybe_unused wf;
drm_WARN_ON(display->drm, test_bit(domain, power_domain_set->mask.bits));
@@ -902,7 +901,7 @@ intel_display_power_get_in_set_if_enabled(struct intel_display *display,
struct intel_display_power_domain_set *power_domain_set,
enum intel_display_power_domain domain)
{
- intel_wakeref_t wf;
+ struct ref_tracker *wf;
drm_WARN_ON(display->drm, test_bit(domain, power_domain_set->mask.bits));
@@ -929,7 +928,7 @@ intel_display_power_put_mask_in_set(struct intel_display *display,
!bitmap_subset(mask->bits, power_domain_set->mask.bits, POWER_DOMAIN_NUM));
for_each_power_domain(domain, mask) {
- intel_wakeref_t __maybe_unused wf = INTEL_WAKEREF_DEF;
+ struct ref_tracker *__maybe_unused wf = INTEL_WAKEREF_DEF;
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
wf = fetch_and_zero(&power_domain_set->wakerefs[domain]);
@@ -1202,7 +1201,6 @@ static void hsw_assert_cdclk(struct intel_display *display)
static void assert_can_disable_lcpll(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc)
@@ -1247,7 +1245,7 @@ static void assert_can_disable_lcpll(struct intel_display *display)
* gen-specific and since we only disable LCPLL after we fully disable
* the interrupts, the check below should be enough.
*/
- INTEL_DISPLAY_STATE_WARN(display, intel_irqs_enabled(dev_priv),
+ INTEL_DISPLAY_STATE_WARN(display, intel_parent_irq_enabled(display),
"IRQs enabled\n");
}
@@ -1341,10 +1339,10 @@ static void hsw_restore_lcpll(struct intel_display *display)
return;
/*
- * Make sure we're not on PC8 state before disabling PC8, otherwise
- * we'll hang the machine. To prevent PC8 state, just enable force_wake.
+ * Make sure we're not on PC8 state before disabling
+ * PC8, otherwise we'll hang the machine.
*/
- intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL);
+ intel_parent_pc8_block(display);
if (val & LCPLL_POWER_DOWN_ALLOW) {
val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -1374,7 +1372,7 @@ static void hsw_restore_lcpll(struct intel_display *display)
"Switching back to LCPLL failed\n");
}
- intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
+ intel_parent_pc8_unblock(display);
intel_update_cdclk(display);
intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK");
@@ -1417,8 +1415,6 @@ static void hsw_enable_pc8(struct intel_display *display)
static void hsw_disable_pc8(struct intel_display *display)
{
- struct drm_i915_private __maybe_unused *dev_priv = to_i915(display->drm);
-
drm_dbg_kms(display->drm, "Disabling package C8+\n");
hsw_restore_lcpll(display);
@@ -1426,7 +1422,7 @@ static void hsw_disable_pc8(struct intel_display *display)
/* Many display registers don't survive PC8+ */
#ifdef I915 /* FIXME */
- intel_clock_gating_init(dev_priv);
+ intel_clock_gating_init(display->drm);
#endif
}
@@ -1618,7 +1614,7 @@ static const struct buddy_page_mask wa_1409767108_buddy_page_masks[] = {
static void tgl_bw_buddy_init(struct intel_display *display)
{
- const struct dram_info *dram_info = intel_dram_info(display->drm);
+ const struct dram_info *dram_info = intel_dram_info(display);
const struct buddy_page_mask *table;
unsigned long abox_mask = DISPLAY_INFO(display)->abox_mask;
int config, i;
@@ -2006,7 +2002,7 @@ void intel_power_domains_init_hw(struct intel_display *display, bool resume)
*/
void intel_power_domains_driver_remove(struct intel_display *display)
{
- intel_wakeref_t wakeref __maybe_unused =
+ struct ref_tracker *wakeref __maybe_unused =
fetch_and_zero(&display->power.domains.init_wakeref);
/* Remove the refcount we took to keep power well support disabled. */
@@ -2067,7 +2063,7 @@ void intel_power_domains_sanitize_state(struct intel_display *display)
*/
void intel_power_domains_enable(struct intel_display *display)
{
- intel_wakeref_t wakeref __maybe_unused =
+ struct ref_tracker *wakeref __maybe_unused =
fetch_and_zero(&display->power.domains.init_wakeref);
intel_display_power_put(display, POWER_DOMAIN_INIT, wakeref);
@@ -2106,7 +2102,7 @@ void intel_power_domains_disable(struct intel_display *display)
void intel_power_domains_suspend(struct intel_display *display, bool s2idle)
{
struct i915_power_domains *power_domains = &display->power.domains;
- intel_wakeref_t wakeref __maybe_unused =
+ struct ref_tracker *wakeref __maybe_unused =
fetch_and_zero(&power_domains->init_wakeref);
intel_display_power_put(display, POWER_DOMAIN_INIT, wakeref);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index f8813b0e16df..d616d5d09cbe 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -9,15 +9,17 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
-#include "intel_wakeref.h"
-
enum aux_ch;
enum port;
struct i915_power_well;
struct intel_display;
struct intel_encoder;
+struct ref_tracker;
struct seq_file;
+/* -ENOENT means we got the ref, but there's no tracking */
+#define INTEL_WAKEREF_DEF ERR_PTR(-ENOENT)
+
/*
* Keep the pipe, transcoder, port (DDI_LANES,DDI_IO,AUX) domain instances
* consecutive, so that the pipe,transcoder,port -> power domain macros
@@ -142,14 +144,14 @@ struct i915_power_domains {
u32 target_dc_state;
u32 allowed_dc_mask;
- intel_wakeref_t init_wakeref;
- intel_wakeref_t disable_wakeref;
+ struct ref_tracker *init_wakeref;
+ struct ref_tracker *disable_wakeref;
struct mutex lock;
int domain_use_count[POWER_DOMAIN_NUM];
struct delayed_work async_put_work;
- intel_wakeref_t async_put_wakeref;
+ struct ref_tracker *async_put_wakeref;
struct intel_power_domain_mask async_put_domains[2];
int async_put_next_delay;
@@ -159,7 +161,7 @@ struct i915_power_domains {
struct intel_display_power_domain_set {
struct intel_power_domain_mask mask;
#ifdef CONFIG_DRM_I915_DEBUG_RUNTIME_PM
- intel_wakeref_t wakerefs[POWER_DOMAIN_NUM];
+ struct ref_tracker *wakerefs[POWER_DOMAIN_NUM];
#endif
};
@@ -187,24 +189,24 @@ u32 intel_display_power_get_current_dc_state(struct intel_display *display);
bool intel_display_power_is_enabled(struct intel_display *display,
enum intel_display_power_domain domain);
-intel_wakeref_t intel_display_power_get(struct intel_display *display,
- enum intel_display_power_domain domain);
-intel_wakeref_t
+struct ref_tracker *intel_display_power_get(struct intel_display *display,
+ enum intel_display_power_domain domain);
+struct ref_tracker *
intel_display_power_get_if_enabled(struct intel_display *display,
enum intel_display_power_domain domain);
void __intel_display_power_put_async(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref,
+ struct ref_tracker *wakeref,
int delay_ms);
void intel_display_power_flush_work(struct intel_display *display);
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
void intel_display_power_put(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref);
+ struct ref_tracker *wakeref);
static inline void
intel_display_power_put_async(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref)
+ struct ref_tracker *wakeref)
{
__intel_display_power_put_async(display, domain, wakeref, -1);
}
@@ -212,7 +214,7 @@ intel_display_power_put_async(struct intel_display *display,
static inline void
intel_display_power_put_async_delay(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref,
+ struct ref_tracker *wakeref,
int delay_ms)
{
__intel_display_power_put_async(display, domain, wakeref, delay_ms);
@@ -224,7 +226,7 @@ void intel_display_power_put_unchecked(struct intel_display *display,
static inline void
intel_display_power_put(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref)
+ struct ref_tracker *wakeref)
{
intel_display_power_put_unchecked(display, domain);
}
@@ -232,7 +234,7 @@ intel_display_power_put(struct intel_display *display,
static inline void
intel_display_power_put_async(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref)
+ struct ref_tracker *wakeref)
{
__intel_display_power_put_async(display, domain, INTEL_WAKEREF_DEF, -1);
}
@@ -240,7 +242,7 @@ intel_display_power_put_async(struct intel_display *display,
static inline void
intel_display_power_put_async_delay(struct intel_display *display,
enum intel_display_power_domain domain,
- intel_wakeref_t wakeref,
+ struct ref_tracker *wakeref,
int delay_ms)
{
__intel_display_power_put_async(display, domain, INTEL_WAKEREF_DEF, delay_ms);
@@ -297,12 +299,18 @@ enum dbuf_slice {
void gen9_dbuf_slices_update(struct intel_display *display,
u8 req_slices);
-#define with_intel_display_power(display, domain, wf) \
- for ((wf) = intel_display_power_get((display), (domain)); (wf); \
+#define __with_intel_display_power(display, domain, wf) \
+ for (struct ref_tracker *(wf) = intel_display_power_get((display), (domain)); (wf); \
intel_display_power_put_async((display), (domain), (wf)), (wf) = NULL)
-#define with_intel_display_power_if_enabled(display, domain, wf) \
- for ((wf) = intel_display_power_get_if_enabled((display), (domain)); (wf); \
+#define with_intel_display_power(display, domain) \
+ __with_intel_display_power(display, domain, __UNIQUE_ID(wakeref))
+
+#define __with_intel_display_power_if_enabled(display, domain, wf) \
+ for (struct ref_tracker *(wf) = intel_display_power_get_if_enabled((display), (domain)); (wf); \
intel_display_power_put_async((display), (domain), (wf)), (wf) = NULL)
+#define with_intel_display_power_if_enabled(display, domain) \
+ __with_intel_display_power_if_enabled(display, domain, __UNIQUE_ID(wakeref))
+
#endif /* __INTEL_DISPLAY_POWER_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c
index f4f7e73acc87..db185a859133 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c
@@ -7,8 +7,6 @@
#include <drm/drm_print.h>
-#include "i915_drv.h"
-#include "i915_irq.h"
#include "i915_reg.h"
#include "intel_backlight_regs.h"
#include "intel_combo_phy.h"
@@ -28,6 +26,7 @@
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_hotplug.h"
+#include "intel_parent.h"
#include "intel_pcode.h"
#include "intel_pps.h"
#include "intel_psr.h"
@@ -258,8 +257,9 @@ aux_ch_to_digital_port(struct intel_display *display,
return NULL;
}
-static enum phy icl_aux_pw_to_phy(struct intel_display *display,
- const struct i915_power_well *power_well)
+static struct intel_encoder *
+icl_aux_pw_to_encoder(struct intel_display *display,
+ const struct i915_power_well *power_well)
{
enum aux_ch aux_ch = icl_aux_pw_to_ch(power_well);
struct intel_digital_port *dig_port = aux_ch_to_digital_port(display, aux_ch);
@@ -271,7 +271,23 @@ static enum phy icl_aux_pw_to_phy(struct intel_display *display,
* as HDMI-only and routed to a combo PHY, the encoder either won't be
* present at all or it will not have an aux_ch assigned.
*/
- return dig_port ? intel_encoder_to_phy(&dig_port->base) : PHY_NONE;
+ return dig_port ? &dig_port->base : NULL;
+}
+
+static enum phy icl_aux_pw_to_phy(struct intel_display *display,
+ const struct i915_power_well *power_well)
+{
+ struct intel_encoder *encoder = icl_aux_pw_to_encoder(display, power_well);
+
+ return encoder ? intel_encoder_to_phy(encoder) : PHY_NONE;
+}
+
+static bool icl_aux_pw_is_tc_phy(struct intel_display *display,
+ const struct i915_power_well *power_well)
+{
+ struct intel_encoder *encoder = icl_aux_pw_to_encoder(display, power_well);
+
+ return encoder && intel_encoder_is_tc(encoder);
}
static void hsw_wait_for_power_well_enable(struct intel_display *display,
@@ -570,9 +586,7 @@ static void
icl_aux_power_well_enable(struct intel_display *display,
struct i915_power_well *power_well)
{
- enum phy phy = icl_aux_pw_to_phy(display, power_well);
-
- if (intel_phy_is_tc(display, phy))
+ if (icl_aux_pw_is_tc_phy(display, power_well))
return icl_tc_phy_aux_power_well_enable(display, power_well);
else if (display->platform.icelake)
return icl_combo_phy_aux_power_well_enable(display,
@@ -585,9 +599,7 @@ static void
icl_aux_power_well_disable(struct intel_display *display,
struct i915_power_well *power_well)
{
- enum phy phy = icl_aux_pw_to_phy(display, power_well);
-
- if (intel_phy_is_tc(display, phy))
+ if (icl_aux_pw_is_tc_phy(display, power_well))
return hsw_power_well_disable(display, power_well);
else if (display->platform.icelake)
return icl_combo_phy_aux_power_well_disable(display,
@@ -628,8 +640,6 @@ static bool hsw_power_well_enabled(struct intel_display *display,
static void assert_can_enable_dc9(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
-
drm_WARN_ONCE(display->drm,
(intel_de_read(display, DC_STATE_EN) & DC_STATE_EN_DC9),
"DC9 already programmed to be enabled.\n");
@@ -641,7 +651,7 @@ static void assert_can_enable_dc9(struct intel_display *display)
intel_de_read(display, HSW_PWR_WELL_CTL2) &
HSW_PWR_WELL_CTL_REQ(SKL_PW_CTL_IDX_PW_2),
"Power well 2 on.\n");
- drm_WARN_ONCE(display->drm, intel_irqs_enabled(dev_priv),
+ drm_WARN_ONCE(display->drm, intel_parent_irq_enabled(display),
"Interrupts not disabled yet.\n");
/*
@@ -655,9 +665,7 @@ static void assert_can_enable_dc9(struct intel_display *display)
static void assert_can_disable_dc9(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
-
- drm_WARN_ONCE(display->drm, intel_irqs_enabled(dev_priv),
+ drm_WARN_ONCE(display->drm, intel_parent_irq_enabled(display),
"Interrupts not disabled yet.\n");
drm_WARN_ONCE(display->drm,
intel_de_read(display, DC_STATE_EN) &
@@ -1281,12 +1289,10 @@ static void vlv_display_power_well_init(struct intel_display *display)
static void vlv_display_power_well_deinit(struct intel_display *display)
{
- struct drm_i915_private *dev_priv = to_i915(display->drm);
-
valleyview_disable_display_irqs(display);
/* make sure we're done processing display irqs */
- intel_synchronize_irq(dev_priv);
+ intel_parent_irq_synchronize(display);
vlv_pps_reset_all(display);
@@ -1852,7 +1858,7 @@ static void xelpdp_aux_power_well_enable(struct intel_display *display,
enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch;
enum phy phy = icl_aux_pw_to_phy(display, power_well);
- if (intel_phy_is_tc(display, phy))
+ if (icl_aux_pw_is_tc_phy(display, power_well))
icl_tc_port_assert_ref_held(display, power_well,
aux_ch_to_digital_port(display, aux_ch));
@@ -1860,19 +1866,19 @@ static void xelpdp_aux_power_well_enable(struct intel_display *display,
XELPDP_DP_AUX_CH_CTL_POWER_REQUEST,
XELPDP_DP_AUX_CH_CTL_POWER_REQUEST);
- /*
- * The power status flag cannot be used to determine whether aux
- * power wells have finished powering up. Instead we're
- * expected to just wait a fixed 600us after raising the request
- * bit.
- */
- if (DISPLAY_VER(display) >= 35) {
+ if (HAS_LT_PHY(display)) {
if (intel_de_wait_for_set_ms(display, XELPDP_DP_AUX_CH_CTL(display, aux_ch),
XELPDP_DP_AUX_CH_CTL_POWER_STATUS, 2))
drm_warn(display->drm,
"Timeout waiting for PHY %c AUX channel power to be up\n",
phy_name(phy));
} else {
+ /*
+ * The power status flag cannot be used to determine whether aux
+ * power wells have finished powering up. Instead we're
+ * expected to just wait a fixed 600us after raising the request
+ * bit.
+ */
usleep_range(600, 1200);
}
}
@@ -1887,7 +1893,7 @@ static void xelpdp_aux_power_well_disable(struct intel_display *display,
XELPDP_DP_AUX_CH_CTL_POWER_REQUEST,
0);
- if (DISPLAY_VER(display) >= 35) {
+ if (HAS_LT_PHY(display)) {
if (intel_de_wait_for_clear_ms(display, XELPDP_DP_AUX_CH_CTL(display, aux_ch),
XELPDP_DP_AUX_CH_CTL_POWER_STATUS, 1))
drm_warn(display->drm,
diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 9d71e26a4fa2..9e0d853f4b61 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -882,6 +882,21 @@
#define PIPE_MISC2_FLIP_INFO_PLANE_SEL_MASK REG_GENMASK(2, 0) /* tgl+ */
#define PIPE_MISC2_FLIP_INFO_PLANE_SEL(plane_id) REG_FIELD_PREP(PIPE_MISC2_FLIP_INFO_PLANE_SEL_MASK, (plane_id))
+#define _UNDERRUN_DBG1_A 0x70064
+#define _UNDERRUN_DBG1_B 0x71064
+#define UNDERRUN_DBG1(pipe) _MMIO_PIPE(pipe, _UNDERRUN_DBG1_A, _UNDERRUN_DBG1_B)
+#define UNDERRUN_DBUF_BLOCK_NOT_VALID_MASK REG_GENMASK(29, 24)
+#define UNDERRUN_DDB_EMPTY_MASK REG_GENMASK(21, 16)
+#define UNDERRUN_DBUF_NOT_FILLED_MASK REG_GENMASK(13, 8)
+#define UNDERRUN_BELOW_WM0_MASK REG_GENMASK(5, 0)
+
+#define _UNDERRUN_DBG2_A 0x70068
+#define _UNDERRUN_DBG2_B 0x71068
+#define UNDERRUN_DBG2(pipe) _MMIO_PIPE(pipe, _UNDERRUN_DBG2_A, _UNDERRUN_DBG2_B)
+#define UNDERRUN_FRAME_LINE_COUNTERS_FROZEN REG_BIT(31)
+#define UNDERRUN_PIPE_FRAME_COUNT_MASK REG_GENMASK(30, 20)
+#define UNDERRUN_LINE_COUNT_MASK REG_GENMASK(19, 0)
+
#define DPINVGTT _MMIO(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */
#define DPINVGTT_EN_MASK_CHV REG_GENMASK(27, 16)
#define DPINVGTT_EN_MASK_VLV REG_GENMASK(23, 16)
@@ -1416,6 +1431,7 @@
#define GEN12_DCPR_STATUS_1 _MMIO(0x46440)
#define XELPDP_PMDEMAND_INFLIGHT_STATUS REG_BIT(26)
+#define XE3P_UNDERRUN_PKGC REG_BIT(21)
#define FUSE_STRAP _MMIO(0x42014)
#define ILK_INTERNAL_GRAPHICS_DISABLE REG_BIT(31)
@@ -2349,8 +2365,13 @@ enum skl_power_gate {
#define DDI_BUF_CTL_TC_PHY_OWNERSHIP REG_BIT(6)
#define DDI_A_4_LANES REG_BIT(4)
#define DDI_PORT_WIDTH_MASK REG_GENMASK(3, 1)
+#define DDI_PORT_WIDTH_ENCODE(width) ((width) == 3 ? 4 : (width) - 1)
+#define DDI_PORT_WIDTH_DECODE(regval) ((regval) == 4 ? 3 : (regval) + 1)
#define DDI_PORT_WIDTH(width) REG_FIELD_PREP(DDI_PORT_WIDTH_MASK, \
- ((width) == 3 ? 4 : (width) - 1))
+ DDI_PORT_WIDTH_ENCODE(width))
+#define DDI_PORT_WIDTH_GET(regval) DDI_PORT_WIDTH_DECODE(REG_FIELD_GET(DDI_PORT_WIDTH_MASK, \
+ (regval)))
+
#define DDI_PORT_WIDTH_SHIFT 1
#define DDI_INIT_DISPLAY_DETECTED REG_BIT(0)
diff --git a/drivers/gpu/drm/i915/display/intel_display_reset.c b/drivers/gpu/drm/i915/display/intel_display_reset.c
index 03e8c68d2913..d00ef5bdcbda 100644
--- a/drivers/gpu/drm/i915/display/intel_display_reset.c
+++ b/drivers/gpu/drm/i915/display/intel_display_reset.c
@@ -6,13 +6,13 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_print.h>
-#include "i915_drv.h"
#include "intel_clock_gating.h"
#include "intel_cx0_phy.h"
#include "intel_display_core.h"
#include "intel_display_driver.h"
#include "intel_display_reset.h"
#include "intel_display_types.h"
+#include "intel_display_utils.h"
#include "intel_hotplug.h"
#include "intel_pps.h"
@@ -79,7 +79,6 @@ bool intel_display_reset_prepare(struct intel_display *display,
void intel_display_reset_finish(struct intel_display *display, bool test_only)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
struct drm_modeset_acquire_ctx *ctx = &display->restore.reset_ctx;
struct drm_atomic_state *state;
int ret;
@@ -107,7 +106,7 @@ void intel_display_reset_finish(struct intel_display *display, bool test_only)
*/
intel_pps_unlock_regs_wa(display);
intel_display_driver_init_hw(display);
- intel_clock_gating_init(i915);
+ intel_clock_gating_init(display->drm);
intel_cx0_pll_power_save_wa(display);
intel_hpd_init(display);
diff --git a/drivers/gpu/drm/i915/display/intel_display_rps.c b/drivers/gpu/drm/i915/display/intel_display_rps.c
index 82ea1ec482e4..e77811396474 100644
--- a/drivers/gpu/drm/i915/display/intel_display_rps.c
+++ b/drivers/gpu/drm/i915/display/intel_display_rps.c
@@ -3,38 +3,39 @@
* Copyright © 2023 Intel Corporation
*/
+#include <linux/dma-fence.h>
+
#include <drm/drm_crtc.h>
#include <drm/drm_vblank.h>
-#include "gt/intel_rps.h"
-#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_display_core.h"
#include "intel_display_irq.h"
#include "intel_display_rps.h"
#include "intel_display_types.h"
+#include "intel_parent.h"
struct wait_rps_boost {
struct wait_queue_entry wait;
struct drm_crtc *crtc;
- struct i915_request *request;
+ struct dma_fence *fence;
};
static int do_rps_boost(struct wait_queue_entry *_wait,
unsigned mode, int sync, void *key)
{
struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait);
- struct i915_request *rq = wait->request;
+ struct intel_display *display = to_intel_display(wait->crtc->dev);
/*
* If we missed the vblank, but the request is already running it
* is reasonable to assume that it will complete before the next
- * vblank without our intervention, so leave RPS alone.
+ * vblank without our intervention, so leave RPS alone if not started.
*/
- if (!i915_request_started(rq))
- intel_rps_boost(rq);
- i915_request_put(rq);
+ intel_parent_rps_boost_if_not_started(display, wait->fence);
+
+ dma_fence_put(wait->fence);
drm_crtc_vblank_put(wait->crtc);
@@ -49,7 +50,7 @@ void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
struct intel_display *display = to_intel_display(crtc->dev);
struct wait_rps_boost *wait;
- if (!dma_fence_is_i915(fence))
+ if (!intel_parent_rps_available(display))
return;
if (DISPLAY_VER(display) < 6)
@@ -64,7 +65,7 @@ void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
return;
}
- wait->request = to_request(dma_fence_get(fence));
+ wait->fence = dma_fence_get(fence);
wait->crtc = crtc;
wait->wait.func = do_rps_boost;
@@ -77,12 +78,14 @@ void intel_display_rps_mark_interactive(struct intel_display *display,
struct intel_atomic_state *state,
bool interactive)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
+ if (!intel_parent_rps_available(display))
+ return;
if (state->rps_interactive == interactive)
return;
- intel_rps_mark_interactive(&to_gt(i915)->rps, interactive);
+ intel_parent_rps_mark_interactive(display, interactive);
+
state->rps_interactive = interactive;
}
@@ -102,7 +105,5 @@ void ilk_display_rps_disable(struct intel_display *display)
void ilk_display_rps_irq_handler(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
-
- gen5_rps_irq_handler(&to_gt(i915)->rps);
+ intel_parent_rps_ilk_irq_handler(display);
}
diff --git a/drivers/gpu/drm/i915/display/intel_display_rps.h b/drivers/gpu/drm/i915/display/intel_display_rps.h
index 183d154f2c7c..96b1fd00ead4 100644
--- a/drivers/gpu/drm/i915/display/intel_display_rps.h
+++ b/drivers/gpu/drm/i915/display/intel_display_rps.h
@@ -13,7 +13,6 @@ struct drm_crtc;
struct intel_atomic_state;
struct intel_display;
-#ifdef I915
void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
struct dma_fence *fence);
void intel_display_rps_mark_interactive(struct intel_display *display,
@@ -22,25 +21,5 @@ void intel_display_rps_mark_interactive(struct intel_display *display,
void ilk_display_rps_enable(struct intel_display *display);
void ilk_display_rps_disable(struct intel_display *display);
void ilk_display_rps_irq_handler(struct intel_display *display);
-#else
-static inline void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
- struct dma_fence *fence)
-{
-}
-static inline void intel_display_rps_mark_interactive(struct intel_display *display,
- struct intel_atomic_state *state,
- bool interactive)
-{
-}
-static inline void ilk_display_rps_enable(struct intel_display *display)
-{
-}
-static inline void ilk_display_rps_disable(struct intel_display *display)
-{
-}
-static inline void ilk_display_rps_irq_handler(struct intel_display *display)
-{
-}
-#endif
#endif /* __INTEL_DISPLAY_RPS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 06bf8f7c0989..6ff53cd58052 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -509,6 +509,12 @@ struct intel_hdcp {
bool force_hdcp14;
};
+enum intel_panel_replay_dsc_support {
+ INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED,
+ INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY,
+ INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE,
+};
+
struct intel_connector {
struct drm_connector base;
/*
@@ -561,6 +567,30 @@ struct intel_connector {
} overall_throughput;
int max_line_width;
} dsc_branch_caps;
+
+ struct {
+ u8 dpcd[DP_PANEL_REPLAY_CAP_SIZE];
+#define INTEL_PR_DPCD_INDEX(pr_dpcd_register) ((pr_dpcd_register) - DP_PANEL_REPLAY_CAP_SUPPORT)
+
+ bool support;
+ bool su_support;
+ enum intel_panel_replay_dsc_support dsc_support;
+
+ u16 su_w_granularity;
+ u16 su_y_granularity;
+ } panel_replay_caps;
+
+ struct {
+ u8 dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
+
+ bool support;
+ bool su_support;
+
+ u16 su_w_granularity;
+ u16 su_y_granularity;
+
+ u8 sync_latency;
+ } psr_caps;
} dp;
struct {
@@ -955,12 +985,6 @@ struct intel_csc_matrix {
u16 postoff[3];
};
-enum intel_panel_replay_dsc_support {
- INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED,
- INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY,
- INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE,
-};
-
struct scaler_filter_coeff {
u16 sign;
u16 exp;
@@ -1152,6 +1176,8 @@ struct intel_crtc_state {
bool enable_psr2_su_region_et;
bool req_psr2_sdp_prior_scanline;
bool has_panel_replay;
+ bool link_off_after_as_sdp_when_pr_active;
+ bool disable_as_sdp_when_pr_active;
bool wm_level_disabled;
bool pkg_c_latency_used;
/* Only used for state verification. */
@@ -1662,7 +1688,7 @@ struct intel_pps {
unsigned long last_power_on;
unsigned long last_backlight_off;
ktime_t panel_power_off_time;
- intel_wakeref_t vdd_wakeref;
+ struct ref_tracker *vdd_wakeref;
union {
/*
@@ -1716,14 +1742,12 @@ struct intel_psr {
bool active;
struct work_struct work;
unsigned int busy_frontbuffer_bits;
- bool sink_psr2_support;
bool link_standby;
bool sel_update_enabled;
bool psr2_sel_fetch_enabled;
bool psr2_sel_fetch_cff_enabled;
bool su_region_et_enabled;
bool req_psr2_sdp_prior_scanline;
- u8 sink_sync_latency;
ktime_t last_entry_attempt;
ktime_t last_exit;
bool sink_not_reliable;
@@ -1732,8 +1756,6 @@ struct intel_psr {
u16 su_y_granularity;
bool source_panel_replay_support;
bool sink_panel_replay_support;
- bool sink_panel_replay_su_support;
- enum intel_panel_replay_dsc_support sink_panel_replay_dsc_support;
bool panel_replay_enabled;
u32 dc3co_exitline;
u32 dc3co_exit_delay;
@@ -1760,9 +1782,6 @@ struct intel_dp {
bool needs_modeset_retry;
bool use_max_params;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
- u8 psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
- u8 pr_dpcd[DP_PANEL_REPLAY_CAP_SIZE];
-#define INTEL_PR_DPCD_INDEX(pr_dpcd_register) ((pr_dpcd_register) - DP_PANEL_REPLAY_CAP_SUPPORT)
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
@@ -1940,12 +1959,13 @@ struct intel_digital_port {
bool lane_reversal;
bool ddi_a_4_lanes;
bool release_cl2_override;
+ bool dedicated_external;
u8 max_lanes;
/* Used for DP and ICL+ TypeC/DP and TypeC/HDMI ports. */
enum aux_ch aux_ch;
enum intel_display_power_domain ddi_io_power_domain;
- intel_wakeref_t ddi_io_wakeref;
- intel_wakeref_t aux_wakeref;
+ struct ref_tracker *ddi_io_wakeref;
+ struct ref_tracker *aux_wakeref;
struct intel_tc_port *tc;
diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c
index e38e5e87877c..a00af39f7538 100644
--- a/drivers/gpu/drm/i915/display/intel_display_wa.c
+++ b/drivers/gpu/drm/i915/display/intel_display_wa.c
@@ -70,6 +70,10 @@ bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa,
return DISPLAY_VER(display) == 13;
case INTEL_DISPLAY_WA_22014263786:
return IS_DISPLAY_VERx100(display, 1100, 1400);
+ case INTEL_DISPLAY_WA_15018326506:
+ return display->platform.battlemage;
+ case INTEL_DISPLAY_WA_14025769978:
+ return DISPLAY_VER(display) == 35;
default:
drm_WARN(display->drm, 1, "Missing Wa number: %s\n", name);
break;
diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h
index 3644e8e2b724..a68c0bb7e516 100644
--- a/drivers/gpu/drm/i915/display/intel_display_wa.h
+++ b/drivers/gpu/drm/i915/display/intel_display_wa.h
@@ -26,6 +26,8 @@ enum intel_display_wa {
INTEL_DISPLAY_WA_16025573575,
INTEL_DISPLAY_WA_14011503117,
INTEL_DISPLAY_WA_22014263786,
+ INTEL_DISPLAY_WA_15018326506,
+ INTEL_DISPLAY_WA_14025769978,
};
bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa, const char *name);
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
index 6ebbd97e6351..2fb6fec6dc99 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -1322,7 +1322,7 @@ static void intel_dmc_runtime_pm_get(struct intel_display *display)
static void intel_dmc_runtime_pm_put(struct intel_display *display)
{
- intel_wakeref_t wakeref __maybe_unused =
+ struct ref_tracker *wakeref __maybe_unused =
fetch_and_zero(&display->dmc.wakeref);
intel_display_power_put(display, POWER_DOMAIN_INIT, wakeref);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 0ec82fcbcf48..2dadbf7e8922 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -424,18 +424,44 @@ static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
return 1;
}
+int intel_dp_link_bw_overhead(int link_clock, int lane_count, int hdisplay,
+ int dsc_slice_count, int bpp_x16, unsigned long flags)
+{
+ int overhead;
+
+ WARN_ON(flags & ~(DRM_DP_BW_OVERHEAD_MST | DRM_DP_BW_OVERHEAD_SSC_REF_CLK |
+ DRM_DP_BW_OVERHEAD_FEC));
+
+ if (drm_dp_is_uhbr_rate(link_clock))
+ flags |= DRM_DP_BW_OVERHEAD_UHBR;
+
+ if (dsc_slice_count)
+ flags |= DRM_DP_BW_OVERHEAD_DSC;
+
+ overhead = drm_dp_bw_overhead(lane_count, hdisplay,
+ dsc_slice_count,
+ bpp_x16,
+ flags);
+
+ /*
+ * TODO: clarify whether a minimum required by the fixed FEC overhead
+ * in the bspec audio programming sequence is required here.
+ */
+ return max(overhead, intel_dp_bw_fec_overhead(flags & DRM_DP_BW_OVERHEAD_FEC));
+}
+
/*
* The required data bandwidth for a mode with given pixel clock and bpp. This
* is the required net bandwidth independent of the data bandwidth efficiency.
- *
- * TODO: check if callers of this functions should use
- * intel_dp_effective_data_rate() instead.
*/
-int
-intel_dp_link_required(int pixel_clock, int bpp)
+int intel_dp_link_required(int link_clock, int lane_count,
+ int mode_clock, int mode_hdisplay,
+ int link_bpp_x16, unsigned long bw_overhead_flags)
{
- /* pixel_clock is in kHz, divide bpp by 8 for bit to Byte conversion */
- return DIV_ROUND_UP(pixel_clock * bpp, 8);
+ int bw_overhead = intel_dp_link_bw_overhead(link_clock, lane_count, mode_hdisplay,
+ 0, link_bpp_x16, bw_overhead_flags);
+
+ return intel_dp_effective_data_rate(mode_clock, link_bpp_x16, bw_overhead);
}
/**
@@ -520,7 +546,8 @@ static int mtl_max_source_rate(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
- if (intel_encoder_is_c10phy(encoder))
+ if (intel_encoder_is_c10phy(encoder) ||
+ display->platform.pantherlake_wildcatlake)
return 810000;
if (DISPLAY_VERx100(display) == 1401)
@@ -1013,6 +1040,8 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector,
int num_joined_pipes)
{
struct intel_display *display = to_intel_display(connector);
+ u32 sink_slice_count_mask =
+ drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, false);
u8 min_slice_count, i;
int max_slice_width;
int tp_rgb_yuv444;
@@ -1084,9 +1113,9 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector,
(!HAS_DSC_3ENGINES(display) || num_joined_pipes != 4))
continue;
- if (test_slice_count >
- drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, false))
- break;
+ if (!(drm_dp_dsc_slice_count_to_mask(test_slice_count) &
+ sink_slice_count_mask))
+ continue;
/*
* Bigjoiner needs small joiner to be enabled.
@@ -1103,8 +1132,14 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector,
return test_slice_count;
}
- drm_dbg_kms(display->drm, "Unsupported Slice Count %d\n",
- min_slice_count);
+ /* Print slice count 1,2,4,..24 if bit#0,1,3,..23 is set in the mask. */
+ sink_slice_count_mask <<= 1;
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Unsupported slice count (min: %d, sink supported: %*pbl)\n",
+ connector->base.base.id, connector->base.name,
+ min_slice_count,
+ (int)BITS_PER_TYPE(sink_slice_count_mask), &sink_slice_count_mask);
+
return 0;
}
@@ -1226,7 +1261,7 @@ int intel_dp_min_bpp(enum intel_output_format output_format)
return 8 * 3;
}
-int intel_dp_output_bpp(enum intel_output_format output_format, int bpp)
+int intel_dp_output_format_link_bpp_x16(enum intel_output_format output_format, int pipe_bpp)
{
/*
* bpp value was assumed to RGB format. And YCbCr 4:2:0 output
@@ -1234,9 +1269,9 @@ int intel_dp_output_bpp(enum intel_output_format output_format, int bpp)
* of bytes of RGB pixel.
*/
if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
- bpp /= 2;
+ pipe_bpp /= 2;
- return bpp;
+ return fxp_q4_from_int(pipe_bpp);
}
static enum intel_output_format
@@ -1252,8 +1287,8 @@ intel_dp_sink_format(struct intel_connector *connector,
}
static int
-intel_dp_mode_min_output_bpp(struct intel_connector *connector,
- const struct drm_display_mode *mode)
+intel_dp_mode_min_link_bpp_x16(struct intel_connector *connector,
+ const struct drm_display_mode *mode)
{
enum intel_output_format output_format, sink_format;
@@ -1261,7 +1296,8 @@ intel_dp_mode_min_output_bpp(struct intel_connector *connector,
output_format = intel_dp_output_format(connector, sink_format);
- return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format));
+ return intel_dp_output_format_link_bpp_x16(output_format,
+ intel_dp_min_bpp(output_format));
}
static bool intel_dp_hdisplay_bad(struct intel_display *display,
@@ -1333,11 +1369,11 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
/* If PCON supports FRL MODE, check FRL bandwidth constraints */
if (intel_dp->dfp.pcon_max_frl_bw) {
+ int link_bpp_x16 = intel_dp_mode_min_link_bpp_x16(connector, mode);
int target_bw;
int max_frl_bw;
- int bpp = intel_dp_mode_min_output_bpp(connector, mode);
- target_bw = bpp * target_clock;
+ target_bw = fxp_q4_to_int_roundup(link_bpp_x16) * target_clock;
max_frl_bw = intel_dp->dfp.pcon_max_frl_bw;
@@ -1452,6 +1488,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
enum drm_mode_status status;
bool dsc = false;
int num_joined_pipes;
+ int link_bpp_x16;
status = intel_cpu_transcoder_mode_valid(display, mode);
if (status != MODE_OK)
@@ -1494,8 +1531,10 @@ intel_dp_mode_valid(struct drm_connector *_connector,
max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes);
- mode_rate = intel_dp_link_required(target_clock,
- intel_dp_mode_min_output_bpp(connector, mode));
+ link_bpp_x16 = intel_dp_mode_min_link_bpp_x16(connector, mode);
+ mode_rate = intel_dp_link_required(max_link_clock, max_lanes,
+ target_clock, mode->hdisplay,
+ link_bpp_x16, 0);
if (intel_dp_has_dsc(connector)) {
int pipe_bpp;
@@ -1802,14 +1841,13 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
const struct link_config_limits *limits)
{
int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state);
- int mode_rate, link_rate, link_avail;
+ int link_rate, link_avail;
for (bpp = fxp_q4_to_int(limits->link.max_bpp_x16);
bpp >= fxp_q4_to_int(limits->link.min_bpp_x16);
bpp -= 2 * 3) {
- int link_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
-
- mode_rate = intel_dp_link_required(clock, link_bpp);
+ int link_bpp_x16 =
+ intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
for (i = 0; i < intel_dp->num_common_rates; i++) {
link_rate = intel_dp_common_rate(intel_dp, i);
@@ -1820,11 +1858,17 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
for (lane_count = limits->min_lane_count;
lane_count <= limits->max_lane_count;
lane_count <<= 1) {
+ const struct drm_display_mode *adjusted_mode =
+ &pipe_config->hw.adjusted_mode;
+ int mode_rate =
+ intel_dp_link_required(link_rate, lane_count,
+ clock, adjusted_mode->hdisplay,
+ link_bpp_x16, 0);
+
link_avail = intel_dp_max_link_data_rate(intel_dp,
link_rate,
lane_count);
-
if (mode_rate <= link_avail) {
pipe_config->lane_count = lane_count;
pipe_config->pipe_bpp = bpp;
@@ -1982,17 +2026,21 @@ static bool intel_dp_dsc_supports_format(const struct intel_connector *connector
return drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, sink_dsc_format);
}
-static bool is_bw_sufficient_for_dsc_config(int dsc_bpp_x16, u32 link_clock,
- u32 lane_count, u32 mode_clock,
- enum intel_output_format output_format,
- int timeslots)
+static bool is_bw_sufficient_for_dsc_config(struct intel_dp *intel_dp,
+ int link_clock, int lane_count,
+ int mode_clock, int mode_hdisplay,
+ int dsc_slice_count, int link_bpp_x16,
+ unsigned long bw_overhead_flags)
{
- u32 available_bw, required_bw;
+ int available_bw;
+ int required_bw;
- available_bw = (link_clock * lane_count * timeslots * 16) / 8;
- required_bw = dsc_bpp_x16 * (intel_dp_mode_to_fec_clock(mode_clock));
+ available_bw = intel_dp_max_link_data_rate(intel_dp, link_clock, lane_count);
+ required_bw = intel_dp_link_required(link_clock, lane_count,
+ mode_clock, mode_hdisplay,
+ link_bpp_x16, bw_overhead_flags);
- return available_bw > required_bw;
+ return available_bw >= required_bw;
}
static int dsc_compute_link_config(struct intel_dp *intel_dp,
@@ -2038,10 +2086,16 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
if (ret)
continue;
} else {
- if (!is_bw_sufficient_for_dsc_config(dsc_bpp_x16, link_rate,
- lane_count, adjusted_mode->clock,
- pipe_config->output_format,
- timeslots))
+ unsigned long bw_overhead_flags =
+ pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
+
+ if (!is_bw_sufficient_for_dsc_config(intel_dp,
+ link_rate, lane_count,
+ adjusted_mode->crtc_clock,
+ adjusted_mode->hdisplay,
+ pipe_config->dsc.slice_count,
+ dsc_bpp_x16,
+ bw_overhead_flags))
continue;
}
@@ -2192,24 +2246,17 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
{
struct intel_display *display = to_intel_display(intel_dp);
const struct intel_connector *connector = to_intel_connector(conn_state->connector);
- const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- int output_bpp;
int min_bpp_x16, max_bpp_x16, bpp_step_x16;
- int dsc_joiner_max_bpp;
- int num_joined_pipes = intel_crtc_num_joined_pipes(pipe_config);
+ int link_bpp_x16;
int bpp_x16;
int ret;
- dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(display, adjusted_mode->clock,
- adjusted_mode->hdisplay,
- num_joined_pipes);
- max_bpp_x16 = min(fxp_q4_from_int(dsc_joiner_max_bpp), limits->link.max_bpp_x16);
-
+ max_bpp_x16 = limits->link.max_bpp_x16;
bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
/* Compressed BPP should be less than the Input DSC bpp */
- output_bpp = intel_dp_output_bpp(pipe_config->output_format, pipe_bpp);
- max_bpp_x16 = min(max_bpp_x16, fxp_q4_from_int(output_bpp) - bpp_step_x16);
+ link_bpp_x16 = intel_dp_output_format_link_bpp_x16(pipe_config->output_format, pipe_bpp);
+ max_bpp_x16 = min(max_bpp_x16, link_bpp_x16 - bpp_step_x16);
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
min_bpp_x16 = round_up(limits->link.min_bpp_x16, bpp_step_x16);
@@ -2560,6 +2607,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp;
int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp;
int throughput_max_bpp_x16;
+ int joiner_max_bpp;
dsc_src_min_bpp = intel_dp_dsc_min_src_compressed_bpp();
dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(crtc_state);
@@ -2567,17 +2615,20 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
limits->link.min_bpp_x16 = fxp_q4_from_int(dsc_min_bpp);
dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp);
+ joiner_max_bpp =
+ get_max_compressed_bpp_with_joiner(display,
+ adjusted_mode->crtc_clock,
+ adjusted_mode->hdisplay,
+ intel_crtc_num_joined_pipes(crtc_state));
dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector,
crtc_state,
limits->pipe.max_bpp / 3);
- dsc_max_bpp = dsc_sink_max_bpp ?
- min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp;
+ dsc_max_bpp = min(dsc_sink_max_bpp, dsc_src_max_bpp);
+ dsc_max_bpp = min(dsc_max_bpp, joiner_max_bpp);
max_link_bpp_x16 = min(max_link_bpp_x16, fxp_q4_from_int(dsc_max_bpp));
throughput_max_bpp_x16 = dsc_throughput_quirk_max_bpp_x16(connector, crtc_state);
- throughput_max_bpp_x16 = clamp(throughput_max_bpp_x16,
- limits->link.min_bpp_x16, max_link_bpp_x16);
if (throughput_max_bpp_x16 < max_link_bpp_x16) {
max_link_bpp_x16 = throughput_max_bpp_x16;
@@ -2592,7 +2643,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
limits->link.max_bpp_x16 = max_link_bpp_x16;
drm_dbg_kms(display->drm,
- "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d max link_bpp " FXP_Q4_FMT "\n",
+ "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
encoder->base.base.id, encoder->base.name,
crtc->base.base.id, crtc->base.name,
adjusted_mode->crtc_clock,
@@ -2600,21 +2651,40 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
limits->max_lane_count,
limits->max_rate,
limits->pipe.max_bpp,
+ FXP_Q4_ARGS(limits->link.min_bpp_x16),
FXP_Q4_ARGS(limits->link.max_bpp_x16));
+ if (limits->link.min_bpp_x16 <= 0 ||
+ limits->link.min_bpp_x16 > limits->link.max_bpp_x16)
+ return false;
+
return true;
}
-static void
-intel_dp_dsc_compute_pipe_bpp_limits(struct intel_dp *intel_dp,
+static bool
+intel_dp_dsc_compute_pipe_bpp_limits(struct intel_connector *connector,
struct link_config_limits *limits)
{
- struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_display *display = to_intel_display(connector);
+ const struct link_config_limits orig_limits = *limits;
int dsc_min_bpc = intel_dp_dsc_min_src_input_bpc();
int dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(display);
- limits->pipe.max_bpp = clamp(limits->pipe.max_bpp, dsc_min_bpc * 3, dsc_max_bpc * 3);
- limits->pipe.min_bpp = clamp(limits->pipe.min_bpp, dsc_min_bpc * 3, dsc_max_bpc * 3);
+ limits->pipe.min_bpp = max(limits->pipe.min_bpp, dsc_min_bpc * 3);
+ limits->pipe.max_bpp = min(limits->pipe.max_bpp, dsc_max_bpc * 3);
+
+ if (limits->pipe.min_bpp <= 0 ||
+ limits->pipe.min_bpp > limits->pipe.max_bpp) {
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Invalid DSC src/sink input BPP (src:%d-%d pipe:%d-%d)\n",
+ connector->base.base.id, connector->base.name,
+ dsc_min_bpc * 3, dsc_max_bpc * 3,
+ orig_limits.pipe.min_bpp, orig_limits.pipe.max_bpp);
+
+ return false;
+ }
+
+ return true;
}
bool
@@ -2654,8 +2724,8 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
respect_downstream_limits);
}
- if (dsc)
- intel_dp_dsc_compute_pipe_bpp_limits(intel_dp, limits);
+ if (dsc && !intel_dp_dsc_compute_pipe_bpp_limits(connector, limits))
+ return false;
if (is_mst || intel_dp->use_max_params) {
/*
@@ -2686,11 +2756,13 @@ int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state)
{
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
- int bpp = crtc_state->dsc.compression_enable ?
- fxp_q4_to_int_roundup(crtc_state->dsc.compressed_bpp_x16) :
- crtc_state->pipe_bpp;
+ int link_bpp_x16 = crtc_state->dsc.compression_enable ?
+ crtc_state->dsc.compressed_bpp_x16 :
+ fxp_q4_from_int(crtc_state->pipe_bpp);
- return intel_dp_link_required(adjusted_mode->crtc_clock, bpp);
+ return intel_dp_link_required(crtc_state->port_clock, crtc_state->lane_count,
+ adjusted_mode->crtc_clock, adjusted_mode->hdisplay,
+ link_bpp_x16, 0);
}
bool intel_dp_joiner_needs_dsc(struct intel_display *display,
@@ -3259,8 +3331,8 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state,
if (crtc_state->dsc.compression_enable)
link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16;
else
- link_bpp_x16 = fxp_q4_from_int(intel_dp_output_bpp(crtc_state->output_format,
- crtc_state->pipe_bpp));
+ link_bpp_x16 = intel_dp_output_format_link_bpp_x16(crtc_state->output_format,
+ crtc_state->pipe_bpp);
/* Calculate min Hblank Link Layer Symbol Cycle Count for 8b/10b MST & 128b/132b */
hactive_sym_cycles = drm_dp_link_symbol_cycles(max_lane_count,
@@ -3370,8 +3442,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (pipe_config->dsc.compression_enable)
link_bpp_x16 = pipe_config->dsc.compressed_bpp_x16;
else
- link_bpp_x16 = fxp_q4_from_int(intel_dp_output_bpp(pipe_config->output_format,
- pipe_config->pipe_bpp));
+ link_bpp_x16 = intel_dp_output_format_link_bpp_x16(pipe_config->output_format,
+ pipe_config->pipe_bpp);
if (intel_dp->mso_link_count) {
int n = intel_dp->mso_link_count;
@@ -4562,7 +4634,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
* This has to be called after intel_dp->edp_dpcd is filled, PSR checks
* for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
*/
- intel_psr_init_dpcd(intel_dp);
+ intel_psr_init_dpcd(intel_dp, connector);
intel_edp_set_sink_rates(intel_dp);
intel_dp_set_max_sink_lane_count(intel_dp);
@@ -5791,9 +5863,8 @@ bool intel_digital_port_connected_locked(struct intel_encoder *encoder)
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool is_glitch_free = intel_tc_port_handles_hpd_glitches(dig_port);
bool is_connected = false;
- intel_wakeref_t wakeref;
- with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) {
+ with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE) {
poll_timeout_us(is_connected = dig_port->connected(encoder),
is_connected || is_glitch_free,
30, 4000, false);
@@ -6049,10 +6120,19 @@ intel_dp_detect(struct drm_connector *_connector,
if (status == connector_status_disconnected) {
intel_dp_test_reset(intel_dp);
+ /*
+ * FIXME: Resetting these caps here cause
+ * state computation fail if the connector need to be
+ * modeset after sink disconnect. Move resetting them
+ * to where new sink is connected.
+ */
memset(connector->dp.dsc_dpcd, 0, sizeof(connector->dp.dsc_dpcd));
+ memset(connector->dp.panel_replay_caps.dpcd, 0,
+ sizeof(connector->dp.panel_replay_caps.dpcd));
intel_dp->psr.sink_panel_replay_support = false;
- intel_dp->psr.sink_panel_replay_su_support = false;
- intel_dp->psr.sink_panel_replay_dsc_support =
+ connector->dp.panel_replay_caps.support = false;
+ connector->dp.panel_replay_caps.su_support = false;
+ connector->dp.panel_replay_caps.dsc_support =
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED;
intel_dp_mst_disconnect(intel_dp);
@@ -6075,7 +6155,7 @@ intel_dp_detect(struct drm_connector *_connector,
connector->base.epoch_counter++;
if (!intel_dp_is_edp(intel_dp))
- intel_psr_init_dpcd(intel_dp);
+ intel_psr_init_dpcd(intel_dp, connector);
intel_dp_detect_dsc_caps(intel_dp, connector);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 200a8b267f64..30eebb8cad6d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -117,7 +117,11 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
bool intel_dp_source_supports_tps3(struct intel_display *display);
bool intel_dp_source_supports_tps4(struct intel_display *display);
-int intel_dp_link_required(int pixel_clock, int bpp);
+int intel_dp_link_bw_overhead(int link_clock, int lane_count, int hdisplay,
+ int dsc_slice_count, int bpp_x16, unsigned long flags);
+int intel_dp_link_required(int link_clock, int lane_count,
+ int mode_clock, int mode_hdisplay,
+ int link_bpp_x16, unsigned long bw_overhead_flags);
int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16,
int bw_overhead);
int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
@@ -193,7 +197,8 @@ void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
void intel_dp_invalidate_source_oui(struct intel_dp *intel_dp);
void intel_dp_wait_source_oui(struct intel_dp *intel_dp);
-int intel_dp_output_bpp(enum intel_output_format output_format, int bpp);
+int intel_dp_output_format_link_bpp_x16(enum intel_output_format output_format,
+ int pipe_bpp);
bool intel_dp_compute_config_limits(struct intel_dp *intel_dp,
struct drm_connector_state *conn_state,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index 809799f63e32..b20ec3e589fa 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -6,6 +6,7 @@
#include <drm/drm_print.h>
#include "intel_de.h"
+#include "intel_display_jiffies.h"
#include "intel_display_types.h"
#include "intel_display_utils.h"
#include "intel_dp.h"
@@ -60,16 +61,17 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
const unsigned int timeout_ms = 10;
u32 status;
- int ret;
+ bool done;
- ret = intel_de_wait_ms(display, ch_ctl,
- DP_AUX_CH_CTL_SEND_BUSY, 0,
- timeout_ms, &status);
+#define C (((status = intel_de_read_notrace(display, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+ done = wait_event_timeout(display->gmbus.wait_queue, C,
+ msecs_to_jiffies_timeout(timeout_ms));
- if (ret == -ETIMEDOUT)
+ if (!done)
drm_err(display->drm,
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
intel_dp->aux.name, timeout_ms, status);
+#undef C
return status;
}
@@ -245,8 +247,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
i915_reg_t ch_ctl, ch_data[5];
u32 aux_clock_divider;
enum intel_display_power_domain aux_domain;
- intel_wakeref_t aux_wakeref;
- intel_wakeref_t pps_wakeref = NULL;
+ struct ref_tracker *aux_wakeref;
+ struct ref_tracker *pps_wakeref = NULL;
int i, ret, recv_bytes;
int try, clock = 0;
u32 status;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index aad5fe14962f..54c585c59b90 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1195,7 +1195,9 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
intel_panel_preferred_fixed_mode(intel_dp->attached_connector);
int mode_rate, max_rate;
- mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
+ mode_rate = intel_dp_link_required(link_rate, lane_count,
+ fixed_mode->clock, fixed_mode->hdisplay,
+ fxp_q4_from_int(18), 0);
max_rate = intel_dp_max_link_data_rate(intel_dp, link_rate, lane_count);
if (mode_rate > max_rate)
return false;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 4c0b943fe86f..0db6ed2d9664 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -180,26 +180,16 @@ static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state,
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
unsigned long flags = DRM_DP_BW_OVERHEAD_MST;
- int overhead;
- flags |= intel_dp_is_uhbr(crtc_state) ? DRM_DP_BW_OVERHEAD_UHBR : 0;
flags |= ssc ? DRM_DP_BW_OVERHEAD_SSC_REF_CLK : 0;
flags |= crtc_state->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
- if (dsc_slice_count)
- flags |= DRM_DP_BW_OVERHEAD_DSC;
-
- overhead = drm_dp_bw_overhead(crtc_state->lane_count,
- adjusted_mode->hdisplay,
- dsc_slice_count,
- bpp_x16,
- flags);
-
- /*
- * TODO: clarify whether a minimum required by the fixed FEC overhead
- * in the bspec audio programming sequence is required here.
- */
- return max(overhead, intel_dp_bw_fec_overhead(crtc_state->fec_enable));
+ return intel_dp_link_bw_overhead(crtc_state->port_clock,
+ crtc_state->lane_count,
+ adjusted_mode->hdisplay,
+ dsc_slice_count,
+ bpp_x16,
+ flags);
}
static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state,
@@ -344,8 +334,8 @@ int intel_dp_mtp_tu_compute_config(struct intel_dp *intel_dp,
}
link_bpp_x16 = dsc ? bpp_x16 :
- fxp_q4_from_int(intel_dp_output_bpp(crtc_state->output_format,
- fxp_q4_to_int(bpp_x16)));
+ intel_dp_output_format_link_bpp_x16(crtc_state->output_format,
+ fxp_q4_to_int(bpp_x16));
local_bw_overhead = intel_dp_mst_bw_overhead(crtc_state,
false, dsc_slice_count, link_bpp_x16);
@@ -1468,6 +1458,8 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
const int min_bpp = 18;
int max_dotclk = display->cdclk.max_dotclk_freq;
int max_rate, mode_rate, max_lanes, max_link_clock;
+ unsigned long bw_overhead_flags =
+ DRM_DP_BW_OVERHEAD_MST | DRM_DP_BW_OVERHEAD_SSC_REF_CLK;
int ret;
bool dsc = false;
u16 dsc_max_compressed_bpp = 0;
@@ -1499,7 +1491,10 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
max_rate = intel_dp_max_link_data_rate(intel_dp,
max_link_clock, max_lanes);
- mode_rate = intel_dp_link_required(mode->clock, min_bpp);
+ mode_rate = intel_dp_link_required(max_link_clock, max_lanes,
+ mode->clock, mode->hdisplay,
+ fxp_q4_from_int(min_bpp),
+ bw_overhead_flags);
/*
* TODO:
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index 4f1db8493a2e..a4f372c9e6fc 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -1212,27 +1212,6 @@ static int dg2_crtc_compute_clock(struct intel_atomic_state *state,
return 0;
}
-static int mtl_crtc_compute_clock(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
-{
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
- struct intel_encoder *encoder =
- intel_get_crtc_new_encoder(state, crtc_state);
- int ret;
-
- ret = intel_cx0pll_calc_state(crtc_state, encoder);
- if (ret)
- return ret;
-
- /* TODO: Do the readback via intel_dpll_compute() */
- crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->dpll_hw_state.cx0pll);
-
- crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state);
-
- return 0;
-}
-
static int xe3plpd_crtc_compute_clock(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -1719,7 +1698,8 @@ static const struct intel_dpll_global_funcs xe3plpd_dpll_funcs = {
};
static const struct intel_dpll_global_funcs mtl_dpll_funcs = {
- .crtc_compute_clock = mtl_crtc_compute_clock,
+ .crtc_compute_clock = hsw_crtc_compute_clock,
+ .crtc_get_dpll = hsw_crtc_get_dpll,
};
static const struct intel_dpll_global_funcs dg2_dpll_funcs = {
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 9c7cf03cf022..9aa84a430f09 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -203,6 +203,22 @@ enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port)
return tc_port - TC_PORT_1 + DPLL_ID_ICL_MGPLL1;
}
+enum intel_dpll_id mtl_port_to_pll_id(struct intel_display *display, enum port port)
+{
+ if (port >= PORT_TC1)
+ return icl_tc_port_to_pll_id(intel_port_to_tc(display, port));
+
+ switch (port) {
+ case PORT_A:
+ return DPLL_ID_ICL_DPLL0;
+ case PORT_B:
+ return DPLL_ID_ICL_DPLL1;
+ default:
+ MISSING_CASE(port);
+ return DPLL_ID_ICL_DPLL0;
+ }
+}
+
static i915_reg_t
intel_combo_pll_enable_reg(struct intel_display *display,
struct intel_dpll *pll)
@@ -531,7 +547,7 @@ static bool ibx_pch_dpll_get_hw_state(struct intel_display *display,
{
struct i9xx_dpll_hw_state *hw_state = &dpll_hw_state->i9xx;
const enum intel_dpll_id id = pll->info->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 val;
wakeref = intel_display_power_get_if_enabled(display,
@@ -752,7 +768,7 @@ static bool hsw_ddi_wrpll_get_hw_state(struct intel_display *display,
{
struct hsw_dpll_hw_state *hw_state = &dpll_hw_state->hsw;
const enum intel_dpll_id id = pll->info->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 val;
wakeref = intel_display_power_get_if_enabled(display,
@@ -773,7 +789,7 @@ static bool hsw_ddi_spll_get_hw_state(struct intel_display *display,
struct intel_dpll_hw_state *dpll_hw_state)
{
struct hsw_dpll_hw_state *hw_state = &dpll_hw_state->hsw;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 val;
wakeref = intel_display_power_get_if_enabled(display,
@@ -1431,7 +1447,7 @@ static bool skl_ddi_pll_get_hw_state(struct intel_display *display,
struct skl_dpll_hw_state *hw_state = &dpll_hw_state->skl;
const struct skl_dpll_regs *regs = skl_dpll_regs;
const enum intel_dpll_id id = pll->info->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
u32 val;
@@ -1469,7 +1485,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct intel_display *display,
struct skl_dpll_hw_state *hw_state = &dpll_hw_state->skl;
const struct skl_dpll_regs *regs = skl_dpll_regs;
const enum intel_dpll_id id = pll->info->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 val;
bool ret;
@@ -2172,7 +2188,7 @@ static bool bxt_ddi_pll_get_hw_state(struct intel_display *display,
{
struct bxt_dpll_hw_state *hw_state = &dpll_hw_state->bxt;
enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum dpio_phy phy;
enum dpio_channel ch;
u32 val;
@@ -3490,6 +3506,37 @@ err_unreference_tbt_pll:
return ret;
}
+/*
+ * Get the PLL for either a port using a C10 PHY PLL, or for a port using a
+ * C20 PHY PLL in the cases of:
+ * - BMG port A/B
+ * - PTL port B eDP over TypeC PHY
+ */
+static int mtl_get_non_tc_phy_dpll(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ struct intel_display *display = to_intel_display(crtc);
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ struct icl_port_dpll *port_dpll =
+ &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ enum intel_dpll_id pll_id = mtl_port_to_pll_id(display, encoder->port);
+
+ port_dpll->pll = intel_find_dpll(state, crtc,
+ &port_dpll->hw_state,
+ BIT(pll_id));
+ if (!port_dpll->pll)
+ return -EINVAL;
+
+ intel_reference_dpll(state, crtc,
+ port_dpll->pll, &port_dpll->hw_state);
+
+ icl_update_active_dpll(state, crtc, encoder);
+
+ return 0;
+}
+
static int icl_compute_dplls(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder)
@@ -3551,7 +3598,7 @@ static bool mg_pll_get_hw_state(struct intel_display *display,
struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl;
const enum intel_dpll_id id = pll->info->id;
enum tc_port tc_port = icl_pll_id_to_tc_port(id);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret = false;
u32 val;
@@ -3618,7 +3665,7 @@ static bool dkl_pll_get_hw_state(struct intel_display *display,
struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl;
const enum intel_dpll_id id = pll->info->id;
enum tc_port tc_port = icl_pll_id_to_tc_port(id);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret = false;
u32 val;
@@ -3690,7 +3737,7 @@ static bool icl_pll_get_hw_state(struct intel_display *display,
{
struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl;
const enum intel_dpll_id id = pll->info->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret = false;
u32 val;
@@ -3753,9 +3800,9 @@ static bool combo_pll_get_hw_state(struct intel_display *display,
return icl_pll_get_hw_state(display, pll, dpll_hw_state, enable_reg);
}
-static bool tbt_pll_get_hw_state(struct intel_display *display,
- struct intel_dpll *pll,
- struct intel_dpll_hw_state *dpll_hw_state)
+static bool icl_tbt_pll_get_hw_state(struct intel_display *display,
+ struct intel_dpll *pll,
+ struct intel_dpll_hw_state *dpll_hw_state)
{
return icl_pll_get_hw_state(display, pll, dpll_hw_state, TBT_PLL_ENABLE);
}
@@ -3984,9 +4031,9 @@ static void combo_pll_enable(struct intel_display *display,
/* DVFS post sequence would be here. See the comment above. */
}
-static void tbt_pll_enable(struct intel_display *display,
- struct intel_dpll *pll,
- const struct intel_dpll_hw_state *dpll_hw_state)
+static void icl_tbt_pll_enable(struct intel_display *display,
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
{
const struct icl_dpll_hw_state *hw_state = &dpll_hw_state->icl;
@@ -4069,8 +4116,8 @@ static void combo_pll_disable(struct intel_display *display,
icl_pll_disable(display, pll, enable_reg);
}
-static void tbt_pll_disable(struct intel_display *display,
- struct intel_dpll *pll)
+static void icl_tbt_pll_disable(struct intel_display *display,
+ struct intel_dpll *pll)
{
icl_pll_disable(display, pll, TBT_PLL_ENABLE);
}
@@ -4142,10 +4189,10 @@ static const struct intel_dpll_funcs combo_pll_funcs = {
.get_freq = icl_ddi_combo_pll_get_freq,
};
-static const struct intel_dpll_funcs tbt_pll_funcs = {
- .enable = tbt_pll_enable,
- .disable = tbt_pll_disable,
- .get_hw_state = tbt_pll_get_hw_state,
+static const struct intel_dpll_funcs icl_tbt_pll_funcs = {
+ .enable = icl_tbt_pll_enable,
+ .disable = icl_tbt_pll_disable,
+ .get_hw_state = icl_tbt_pll_get_hw_state,
.get_freq = icl_ddi_tbt_pll_get_freq,
};
@@ -4159,7 +4206,7 @@ static const struct intel_dpll_funcs mg_pll_funcs = {
static const struct dpll_info icl_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
- { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+ { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
.is_alt_port_dpll = true, },
{ .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
@@ -4207,7 +4254,7 @@ static const struct intel_dpll_funcs dkl_pll_funcs = {
static const struct dpll_info tgl_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
- { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+ { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
.is_alt_port_dpll = true, },
{ .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
@@ -4285,7 +4332,7 @@ static const struct intel_dpll_mgr adls_pll_mgr = {
static const struct dpll_info adlp_plls[] = {
{ .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
{ .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
- { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+ { .name = "TBT PLL", .funcs = &icl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
.is_alt_port_dpll = true, },
{ .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
{ .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
@@ -4305,6 +4352,224 @@ static const struct intel_dpll_mgr adlp_pll_mgr = {
.compare_hw_state = icl_compare_hw_state,
};
+static struct intel_encoder *get_intel_encoder(struct intel_display *display,
+ const struct intel_dpll *pll)
+{
+ struct intel_encoder *encoder;
+ enum intel_dpll_id mtl_id;
+
+ for_each_intel_encoder(display->drm, encoder) {
+ mtl_id = mtl_port_to_pll_id(display, encoder->port);
+
+ if (mtl_id == pll->info->id)
+ return encoder;
+ }
+
+ return NULL;
+}
+
+static bool mtl_pll_get_hw_state(struct intel_display *display,
+ struct intel_dpll *pll,
+ struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = get_intel_encoder(display, pll);
+
+ if (!encoder)
+ return false;
+
+ return intel_cx0pll_readout_hw_state(encoder, &dpll_hw_state->cx0pll);
+}
+
+static int mtl_pll_get_freq(struct intel_display *display,
+ const struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return -EINVAL;
+
+ return intel_cx0pll_calc_port_clock(encoder, &dpll_hw_state->cx0pll);
+}
+
+static void mtl_pll_enable(struct intel_display *display,
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return;
+
+ intel_mtl_pll_enable(encoder, pll, dpll_hw_state);
+}
+
+static void mtl_pll_disable(struct intel_display *display,
+ struct intel_dpll *pll)
+{
+ struct intel_encoder *encoder = get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return;
+
+ intel_mtl_pll_disable(encoder);
+}
+
+static const struct intel_dpll_funcs mtl_pll_funcs = {
+ .enable = mtl_pll_enable,
+ .disable = mtl_pll_disable,
+ .get_hw_state = mtl_pll_get_hw_state,
+ .get_freq = mtl_pll_get_freq,
+};
+
+static void mtl_tbt_pll_enable(struct intel_display *display,
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *hw_state)
+{
+}
+
+static void mtl_tbt_pll_disable(struct intel_display *display,
+ struct intel_dpll *pll)
+{
+}
+
+static int mtl_tbt_pll_get_freq(struct intel_display *display,
+ const struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ /*
+ * The PLL outputs multiple frequencies at the same time, selection is
+ * made at DDI clock mux level.
+ */
+ drm_WARN_ON(display->drm, 1);
+
+ return 0;
+}
+
+static const struct intel_dpll_funcs mtl_tbt_pll_funcs = {
+ .enable = mtl_tbt_pll_enable,
+ .disable = mtl_tbt_pll_disable,
+ .get_hw_state = intel_mtl_tbt_pll_readout_hw_state,
+ .get_freq = mtl_tbt_pll_get_freq,
+};
+
+static const struct dpll_info mtl_plls[] = {
+ { .name = "DPLL 0", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
+ { .name = "DPLL 1", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
+ { .name = "TBT PLL", .funcs = &mtl_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+ .is_alt_port_dpll = true, .always_on = true },
+ { .name = "TC PLL 1", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
+ { .name = "TC PLL 2", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
+ { .name = "TC PLL 3", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
+ { .name = "TC PLL 4", .funcs = &mtl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, },
+ {}
+};
+
+/*
+ * Compute the state for either a C10 PHY PLL, or in the case of the PTL port B,
+ * eDP on TypeC PHY case for a C20 PHY PLL.
+ */
+static int mtl_compute_non_tc_phy_dpll(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ struct icl_port_dpll *port_dpll =
+ &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ int ret;
+
+ ret = intel_cx0pll_calc_state(crtc_state, encoder, &port_dpll->hw_state);
+ if (ret)
+ return ret;
+
+ /* this is mainly for the fastset check */
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
+
+ crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder,
+ &port_dpll->hw_state.cx0pll);
+
+ return 0;
+}
+
+static int mtl_compute_tc_phy_dplls(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ const struct intel_crtc_state *old_crtc_state =
+ intel_atomic_get_old_crtc_state(state, crtc);
+ struct icl_port_dpll *port_dpll;
+ int ret;
+
+ port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ intel_mtl_tbt_pll_calc_state(&port_dpll->hw_state);
+
+ port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
+ ret = intel_cx0pll_calc_state(crtc_state, encoder, &port_dpll->hw_state);
+ if (ret)
+ return ret;
+
+ /* this is mainly for the fastset check */
+ if (old_crtc_state->intel_dpll &&
+ old_crtc_state->intel_dpll->info->id == DPLL_ID_ICL_TBTPLL)
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
+ else
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY);
+
+ crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder,
+ &port_dpll->hw_state.cx0pll);
+
+ return 0;
+}
+
+static int mtl_compute_dplls(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ if (intel_encoder_is_tc(encoder))
+ return mtl_compute_tc_phy_dplls(state, crtc, encoder);
+ else
+ return mtl_compute_non_tc_phy_dpll(state, crtc, encoder);
+}
+
+static int mtl_get_dplls(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ if (intel_encoder_is_tc(encoder))
+ return icl_get_tc_phy_dplls(state, crtc, encoder);
+ else
+ return mtl_get_non_tc_phy_dpll(state, crtc, encoder);
+}
+
+static void mtl_dump_hw_state(struct drm_printer *p,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ intel_cx0pll_dump_hw_state(p, &dpll_hw_state->cx0pll);
+}
+
+static bool mtl_compare_hw_state(const struct intel_dpll_hw_state *_a,
+ const struct intel_dpll_hw_state *_b)
+{
+ const struct intel_cx0pll_state *a = &_a->cx0pll;
+ const struct intel_cx0pll_state *b = &_b->cx0pll;
+
+ return intel_cx0pll_compare_hw_state(a, b);
+}
+
+static const struct intel_dpll_mgr mtl_pll_mgr = {
+ .dpll_info = mtl_plls,
+ .compute_dplls = mtl_compute_dplls,
+ .get_dplls = mtl_get_dplls,
+ .put_dplls = icl_put_dplls,
+ .update_active_dpll = icl_update_active_dpll,
+ .update_ref_clks = icl_update_dpll_ref_clks,
+ .dump_hw_state = mtl_dump_hw_state,
+ .compare_hw_state = mtl_compare_hw_state,
+};
+
/**
* intel_dpll_init - Initialize DPLLs
* @display: intel_display device
@@ -4319,9 +4584,11 @@ void intel_dpll_init(struct intel_display *display)
mutex_init(&display->dpll.lock);
- if (DISPLAY_VER(display) >= 14 || display->platform.dg2)
- /* No shared DPLLs on DG2; port PLLs are part of the PHY */
+ if (DISPLAY_VER(display) >= 35 || display->platform.dg2)
+ /* No shared DPLLs on NVL or DG2; port PLLs are part of the PHY */
dpll_mgr = NULL;
+ else if (DISPLAY_VER(display) >= 14)
+ dpll_mgr = &mtl_pll_mgr;
else if (display->platform.alderlake_p)
dpll_mgr = &adlp_pll_mgr;
else if (display->platform.alderlake_s)
@@ -4675,11 +4942,18 @@ verify_single_dpll_state(struct intel_display *display,
"%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n",
pll->info->name, pipe_mask, pll->state.pipe_mask);
- INTEL_DISPLAY_STATE_WARN(display,
- pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state,
- sizeof(dpll_hw_state)),
- "%s: pll hw state mismatch\n",
- pll->info->name);
+ if (INTEL_DISPLAY_STATE_WARN(display,
+ pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state,
+ sizeof(dpll_hw_state)),
+ "%s: pll hw state mismatch\n",
+ pll->info->name)) {
+ struct drm_printer p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL);
+
+ drm_printf(&p, "PLL %s HW state:\n", pll->info->name);
+ intel_dpll_dump_hw_state(display, &p, &dpll_hw_state);
+ drm_printf(&p, "PLL %s SW state:\n", pll->info->name);
+ intel_dpll_dump_hw_state(display, &p, &pll->state.hw_state);
+ }
}
static bool has_alt_port_dpll(const struct intel_dpll *old_pll,
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index 6183da90b28d..5b71c860515f 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -28,7 +28,6 @@
#include <linux/types.h>
#include "intel_display_power.h"
-#include "intel_wakeref.h"
#define for_each_dpll(__display, __pll, __i) \
for ((__i) = 0; (__i) < (__display)->dpll.num_dpll && \
@@ -42,6 +41,7 @@ struct intel_crtc_state;
struct intel_dpll_funcs;
struct intel_encoder;
struct intel_shared_dpll;
+struct ref_tracker;
/**
* enum intel_dpll_id - possible DPLL ids
@@ -255,6 +255,11 @@ struct intel_c20pll_state {
u16 mplla[10];
u16 mpllb[11];
};
+ struct intel_c20pll_vdr_state {
+ u8 custom_width;
+ u8 serdes_rate;
+ u8 hdmi_rate;
+ } vdr;
};
struct intel_cx0pll_state {
@@ -262,6 +267,7 @@ struct intel_cx0pll_state {
struct intel_c10pll_state c10;
struct intel_c20pll_state c20;
};
+ int lane_count;
bool ssc_enabled;
bool use_c10;
bool tbt_mode;
@@ -390,7 +396,7 @@ struct intel_dpll {
* @wakeref: In some platforms a device-level runtime pm reference may
* need to be grabbed to disable DC states while this DPLL is enabled
*/
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
};
#define SKL_DPLL0 0
@@ -444,6 +450,7 @@ bool intel_dpll_compare_hw_state(struct intel_display *display,
const struct intel_dpll_hw_state *a,
const struct intel_dpll_hw_state *b);
enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port);
+enum intel_dpll_id mtl_port_to_pll_id(struct intel_display *display, enum port port);
bool intel_dpll_is_combophy(enum intel_dpll_id id);
void intel_dpll_state_verify(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c
index 3e588762709a..019a722a38bf 100644
--- a/drivers/gpu/drm/i915/soc/intel_dram.c
+++ b/drivers/gpu/drm/i915/display/intel_dram.c
@@ -8,11 +8,10 @@
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
-#include "../display/intel_display_core.h" /* FIXME */
-
#include "i915_drv.h"
#include "i915_reg.h"
-#include "i915_utils.h"
+#include "intel_display_core.h"
+#include "intel_display_utils.h"
#include "intel_dram.h"
#include "intel_mchbar_regs.h"
#include "intel_pcode.h"
@@ -57,14 +56,17 @@ const char *intel_dram_type_str(enum intel_dram_type type)
#undef DRAM_TYPE_STR
-static enum intel_dram_type pnv_dram_type(struct drm_i915_private *i915)
+static enum intel_dram_type pnv_dram_type(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
+
return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ?
INTEL_DRAM_DDR3 : INTEL_DRAM_DDR2;
}
-static unsigned int pnv_mem_freq(struct drm_i915_private *dev_priv)
+static unsigned int pnv_mem_freq(struct intel_display *display)
{
+ struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 tmp;
tmp = intel_uncore_read(&dev_priv->uncore, CLKCFG);
@@ -81,8 +83,9 @@ static unsigned int pnv_mem_freq(struct drm_i915_private *dev_priv)
return 0;
}
-static unsigned int ilk_mem_freq(struct drm_i915_private *dev_priv)
+static unsigned int ilk_mem_freq(struct intel_display *display)
{
+ struct drm_i915_private *dev_priv = to_i915(display->drm);
u16 ddrpll;
ddrpll = intel_uncore_read16(&dev_priv->uncore, DDRMPLL1);
@@ -96,19 +99,19 @@ static unsigned int ilk_mem_freq(struct drm_i915_private *dev_priv)
case 0x18:
return 1600000;
default:
- drm_dbg(&dev_priv->drm, "unknown memory frequency 0x%02x\n",
- ddrpll & 0xff);
+ drm_dbg_kms(display->drm, "unknown memory frequency 0x%02x\n",
+ ddrpll & 0xff);
return 0;
}
}
-static unsigned int chv_mem_freq(struct drm_i915_private *i915)
+static unsigned int chv_mem_freq(struct intel_display *display)
{
u32 val;
- vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_CCK));
- val = vlv_iosf_sb_read(&i915->drm, VLV_IOSF_SB_CCK, CCK_FUSE_REG);
- vlv_iosf_sb_put(&i915->drm, BIT(VLV_IOSF_SB_CCK));
+ vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK));
+ val = vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_CCK, CCK_FUSE_REG);
+ vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_CCK));
switch ((val >> 2) & 0x7) {
case 3:
@@ -118,13 +121,13 @@ static unsigned int chv_mem_freq(struct drm_i915_private *i915)
}
}
-static unsigned int vlv_mem_freq(struct drm_i915_private *i915)
+static unsigned int vlv_mem_freq(struct intel_display *display)
{
u32 val;
- vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT));
- val = vlv_iosf_sb_read(&i915->drm, VLV_IOSF_SB_PUNIT, PUNIT_REG_GPU_FREQ_STS);
- vlv_iosf_sb_put(&i915->drm, BIT(VLV_IOSF_SB_PUNIT));
+ vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_PUNIT));
+ val = vlv_iosf_sb_read(display->drm, VLV_IOSF_SB_PUNIT, PUNIT_REG_GPU_FREQ_STS);
+ vlv_iosf_sb_put(display->drm, BIT(VLV_IOSF_SB_PUNIT));
switch ((val >> 6) & 3) {
case 0:
@@ -139,22 +142,23 @@ static unsigned int vlv_mem_freq(struct drm_i915_private *i915)
return 0;
}
-unsigned int intel_mem_freq(struct drm_i915_private *i915)
+unsigned int intel_mem_freq(struct intel_display *display)
{
- if (IS_PINEVIEW(i915))
- return pnv_mem_freq(i915);
- else if (GRAPHICS_VER(i915) == 5)
- return ilk_mem_freq(i915);
- else if (IS_CHERRYVIEW(i915))
- return chv_mem_freq(i915);
- else if (IS_VALLEYVIEW(i915))
- return vlv_mem_freq(i915);
+ if (display->platform.pineview)
+ return pnv_mem_freq(display);
+ else if (DISPLAY_VER(display) == 5)
+ return ilk_mem_freq(display);
+ else if (display->platform.cherryview)
+ return chv_mem_freq(display);
+ else if (display->platform.valleyview)
+ return vlv_mem_freq(display);
else
return 0;
}
-static unsigned int i9xx_fsb_freq(struct drm_i915_private *i915)
+static unsigned int i9xx_fsb_freq(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
u32 fsb;
/*
@@ -167,7 +171,7 @@ static unsigned int i9xx_fsb_freq(struct drm_i915_private *i915)
*/
fsb = intel_uncore_read(&i915->uncore, CLKCFG) & CLKCFG_FSB_MASK;
- if (IS_PINEVIEW(i915) || IS_MOBILE(i915)) {
+ if (display->platform.pineview || display->platform.mobile) {
switch (fsb) {
case CLKCFG_FSB_400:
return 400000;
@@ -208,8 +212,9 @@ static unsigned int i9xx_fsb_freq(struct drm_i915_private *i915)
}
}
-static unsigned int ilk_fsb_freq(struct drm_i915_private *dev_priv)
+static unsigned int ilk_fsb_freq(struct intel_display *display)
{
+ struct drm_i915_private *dev_priv = to_i915(display->drm);
u16 fsb;
fsb = intel_uncore_read16(&dev_priv->uncore, CSIPLL0) & 0x3ff;
@@ -230,33 +235,33 @@ static unsigned int ilk_fsb_freq(struct drm_i915_private *dev_priv)
case 0x018:
return 6400000;
default:
- drm_dbg(&dev_priv->drm, "unknown fsb frequency 0x%04x\n", fsb);
+ drm_dbg_kms(display->drm, "unknown fsb frequency 0x%04x\n", fsb);
return 0;
}
}
-unsigned int intel_fsb_freq(struct drm_i915_private *i915)
+unsigned int intel_fsb_freq(struct intel_display *display)
{
- if (GRAPHICS_VER(i915) == 5)
- return ilk_fsb_freq(i915);
- else if (GRAPHICS_VER(i915) == 3 || GRAPHICS_VER(i915) == 4)
- return i9xx_fsb_freq(i915);
+ if (DISPLAY_VER(display) == 5)
+ return ilk_fsb_freq(display);
+ else if (IS_DISPLAY_VER(display, 3, 4))
+ return i9xx_fsb_freq(display);
else
return 0;
}
-static int i915_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+static int i915_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
- dram_info->fsb_freq = intel_fsb_freq(i915);
+ dram_info->fsb_freq = intel_fsb_freq(display);
if (dram_info->fsb_freq)
- drm_dbg(&i915->drm, "FSB frequency: %d kHz\n", dram_info->fsb_freq);
+ drm_dbg_kms(display->drm, "FSB frequency: %d kHz\n", dram_info->fsb_freq);
- dram_info->mem_freq = intel_mem_freq(i915);
+ dram_info->mem_freq = intel_mem_freq(display);
if (dram_info->mem_freq)
- drm_dbg(&i915->drm, "DDR speed: %d kHz\n", dram_info->mem_freq);
+ drm_dbg_kms(display->drm, "DDR speed: %d kHz\n", dram_info->mem_freq);
- if (IS_PINEVIEW(i915))
- dram_info->type = pnv_dram_type(i915);
+ if (display->platform.pineview)
+ dram_info->type = pnv_dram_type(display);
return 0;
}
@@ -267,69 +272,121 @@ static int intel_dimm_num_devices(const struct dram_dimm_info *dimm)
}
/* Returns total Gb for the whole DIMM */
-static int skl_get_dimm_size(u16 val)
+static int skl_get_dimm_s_size(u32 val)
+{
+ return REG_FIELD_GET(SKL_DIMM_S_SIZE_MASK, val) * 8;
+}
+
+static int skl_get_dimm_l_size(u32 val)
{
- return (val & SKL_DRAM_SIZE_MASK) * 8;
+ return REG_FIELD_GET(SKL_DIMM_L_SIZE_MASK, val) * 8;
}
-static int skl_get_dimm_width(u16 val)
+static int skl_get_dimm_s_width(u32 val)
{
- if (skl_get_dimm_size(val) == 0)
+ if (skl_get_dimm_s_size(val) == 0)
return 0;
- switch (val & SKL_DRAM_WIDTH_MASK) {
- case SKL_DRAM_WIDTH_X8:
- case SKL_DRAM_WIDTH_X16:
- case SKL_DRAM_WIDTH_X32:
- val = (val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT;
- return 8 << val;
+ switch (val & SKL_DIMM_S_WIDTH_MASK) {
+ case SKL_DIMM_S_WIDTH_X8:
+ case SKL_DIMM_S_WIDTH_X16:
+ case SKL_DIMM_S_WIDTH_X32:
+ return 8 << REG_FIELD_GET(SKL_DIMM_S_WIDTH_MASK, val);
default:
MISSING_CASE(val);
return 0;
}
}
-static int skl_get_dimm_ranks(u16 val)
+static int skl_get_dimm_l_width(u32 val)
{
- if (skl_get_dimm_size(val) == 0)
+ if (skl_get_dimm_l_size(val) == 0)
return 0;
- val = (val & SKL_DRAM_RANK_MASK) >> SKL_DRAM_RANK_SHIFT;
+ switch (val & SKL_DIMM_L_WIDTH_MASK) {
+ case SKL_DIMM_L_WIDTH_X8:
+ case SKL_DIMM_L_WIDTH_X16:
+ case SKL_DIMM_L_WIDTH_X32:
+ return 8 << REG_FIELD_GET(SKL_DIMM_L_WIDTH_MASK, val);
+ default:
+ MISSING_CASE(val);
+ return 0;
+ }
+}
+
+static int skl_get_dimm_s_ranks(u32 val)
+{
+ if (skl_get_dimm_s_size(val) == 0)
+ return 0;
+
+ return REG_FIELD_GET(SKL_DIMM_S_RANK_MASK, val) + 1;
+}
+
+static int skl_get_dimm_l_ranks(u32 val)
+{
+ if (skl_get_dimm_l_size(val) == 0)
+ return 0;
- return val + 1;
+ return REG_FIELD_GET(SKL_DIMM_L_RANK_MASK, val) + 1;
}
/* Returns total Gb for the whole DIMM */
-static int icl_get_dimm_size(u16 val)
+static int icl_get_dimm_s_size(u32 val)
{
- return (val & ICL_DRAM_SIZE_MASK) * 8 / 2;
+ return REG_FIELD_GET(ICL_DIMM_S_SIZE_MASK, val) * 8 / 2;
}
-static int icl_get_dimm_width(u16 val)
+static int icl_get_dimm_l_size(u32 val)
{
- if (icl_get_dimm_size(val) == 0)
+ return REG_FIELD_GET(ICL_DIMM_L_SIZE_MASK, val) * 8 / 2;
+}
+
+static int icl_get_dimm_s_width(u32 val)
+{
+ if (icl_get_dimm_s_size(val) == 0)
return 0;
- switch (val & ICL_DRAM_WIDTH_MASK) {
- case ICL_DRAM_WIDTH_X8:
- case ICL_DRAM_WIDTH_X16:
- case ICL_DRAM_WIDTH_X32:
- val = (val & ICL_DRAM_WIDTH_MASK) >> ICL_DRAM_WIDTH_SHIFT;
- return 8 << val;
+ switch (val & ICL_DIMM_S_WIDTH_MASK) {
+ case ICL_DIMM_S_WIDTH_X8:
+ case ICL_DIMM_S_WIDTH_X16:
+ case ICL_DIMM_S_WIDTH_X32:
+ return 8 << REG_FIELD_GET(ICL_DIMM_S_WIDTH_MASK, val);
default:
MISSING_CASE(val);
return 0;
}
}
-static int icl_get_dimm_ranks(u16 val)
+static int icl_get_dimm_l_width(u32 val)
{
- if (icl_get_dimm_size(val) == 0)
+ if (icl_get_dimm_l_size(val) == 0)
return 0;
- val = (val & ICL_DRAM_RANK_MASK) >> ICL_DRAM_RANK_SHIFT;
+ switch (val & ICL_DIMM_L_WIDTH_MASK) {
+ case ICL_DIMM_L_WIDTH_X8:
+ case ICL_DIMM_L_WIDTH_X16:
+ case ICL_DIMM_L_WIDTH_X32:
+ return 8 << REG_FIELD_GET(ICL_DIMM_L_WIDTH_MASK, val);
+ default:
+ MISSING_CASE(val);
+ return 0;
+ }
+}
+
+static int icl_get_dimm_s_ranks(u32 val)
+{
+ if (icl_get_dimm_s_size(val) == 0)
+ return 0;
+
+ return REG_FIELD_GET(ICL_DIMM_S_RANK_MASK, val) + 1;
+}
+
+static int icl_get_dimm_l_ranks(u32 val)
+{
+ if (icl_get_dimm_l_size(val) == 0)
+ return 0;
- return val + 1;
+ return REG_FIELD_GET(ICL_DIMM_L_RANK_MASK, val) + 1;
}
static bool
@@ -340,38 +397,62 @@ skl_is_16gb_dimm(const struct dram_dimm_info *dimm)
}
static void
-skl_dram_get_dimm_info(struct drm_i915_private *i915,
- struct dram_dimm_info *dimm,
- int channel, char dimm_name, u16 val)
-{
- if (GRAPHICS_VER(i915) >= 11) {
- dimm->size = icl_get_dimm_size(val);
- dimm->width = icl_get_dimm_width(val);
- dimm->ranks = icl_get_dimm_ranks(val);
- } else {
- dimm->size = skl_get_dimm_size(val);
- dimm->width = skl_get_dimm_width(val);
- dimm->ranks = skl_get_dimm_ranks(val);
- }
-
- drm_dbg_kms(&i915->drm,
+skl_dram_print_dimm_info(struct intel_display *display,
+ struct dram_dimm_info *dimm,
+ int channel, char dimm_name)
+{
+ drm_dbg_kms(display->drm,
"CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb+ DIMMs: %s\n",
channel, dimm_name, dimm->size, dimm->width, dimm->ranks,
str_yes_no(skl_is_16gb_dimm(dimm)));
}
+static void
+skl_dram_get_dimm_l_info(struct intel_display *display,
+ struct dram_dimm_info *dimm,
+ int channel, u32 val)
+{
+ if (DISPLAY_VER(display) >= 11) {
+ dimm->size = icl_get_dimm_l_size(val);
+ dimm->width = icl_get_dimm_l_width(val);
+ dimm->ranks = icl_get_dimm_l_ranks(val);
+ } else {
+ dimm->size = skl_get_dimm_l_size(val);
+ dimm->width = skl_get_dimm_l_width(val);
+ dimm->ranks = skl_get_dimm_l_ranks(val);
+ }
+
+ skl_dram_print_dimm_info(display, dimm, channel, 'L');
+}
+
+static void
+skl_dram_get_dimm_s_info(struct intel_display *display,
+ struct dram_dimm_info *dimm,
+ int channel, u32 val)
+{
+ if (DISPLAY_VER(display) >= 11) {
+ dimm->size = icl_get_dimm_s_size(val);
+ dimm->width = icl_get_dimm_s_width(val);
+ dimm->ranks = icl_get_dimm_s_ranks(val);
+ } else {
+ dimm->size = skl_get_dimm_s_size(val);
+ dimm->width = skl_get_dimm_s_width(val);
+ dimm->ranks = skl_get_dimm_s_ranks(val);
+ }
+
+ skl_dram_print_dimm_info(display, dimm, channel, 'S');
+}
+
static int
-skl_dram_get_channel_info(struct drm_i915_private *i915,
+skl_dram_get_channel_info(struct intel_display *display,
struct dram_channel_info *ch,
int channel, u32 val)
{
- skl_dram_get_dimm_info(i915, &ch->dimm_l,
- channel, 'L', val & 0xffff);
- skl_dram_get_dimm_info(i915, &ch->dimm_s,
- channel, 'S', val >> 16);
+ skl_dram_get_dimm_l_info(display, &ch->dimm_l, channel, val);
+ skl_dram_get_dimm_s_info(display, &ch->dimm_s, channel, val);
if (ch->dimm_l.size == 0 && ch->dimm_s.size == 0) {
- drm_dbg_kms(&i915->drm, "CH%u not populated\n", channel);
+ drm_dbg_kms(display->drm, "CH%u not populated\n", channel);
return -EINVAL;
}
@@ -385,7 +466,7 @@ skl_dram_get_channel_info(struct drm_i915_private *i915,
ch->is_16gb_dimm = skl_is_16gb_dimm(&ch->dimm_l) ||
skl_is_16gb_dimm(&ch->dimm_s);
- drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb+ DIMMs: %s\n",
+ drm_dbg_kms(display->drm, "CH%u ranks: %u, 16Gb+ DIMMs: %s\n",
channel, ch->ranks, str_yes_no(ch->is_16gb_dimm));
return 0;
@@ -401,8 +482,9 @@ intel_is_dram_symmetric(const struct dram_channel_info *ch0,
}
static int
-skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram_info)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
struct dram_channel_info ch0 = {}, ch1 = {};
u32 val;
int ret;
@@ -412,23 +494,23 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram
val = intel_uncore_read(&i915->uncore,
SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
- ret = skl_dram_get_channel_info(i915, &ch0, 0, val);
+ ret = skl_dram_get_channel_info(display, &ch0, 0, val);
if (ret == 0)
dram_info->num_channels++;
val = intel_uncore_read(&i915->uncore,
SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
- ret = skl_dram_get_channel_info(i915, &ch1, 1, val);
+ ret = skl_dram_get_channel_info(display, &ch1, 1, val);
if (ret == 0)
dram_info->num_channels++;
if (dram_info->num_channels == 0) {
- drm_info(&i915->drm, "Number of memory channels is zero\n");
+ drm_info(display->drm, "Number of memory channels is zero\n");
return -EINVAL;
}
if (ch0.ranks == 0 && ch1.ranks == 0) {
- drm_info(&i915->drm, "couldn't get memory rank information\n");
+ drm_info(display->drm, "couldn't get memory rank information\n");
return -EINVAL;
}
@@ -436,18 +518,19 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram
dram_info->symmetric_memory = intel_is_dram_symmetric(&ch0, &ch1);
- drm_dbg_kms(&i915->drm, "Memory configuration is symmetric? %s\n",
+ drm_dbg_kms(display->drm, "Memory configuration is symmetric? %s\n",
str_yes_no(dram_info->symmetric_memory));
- drm_dbg_kms(&i915->drm, "16Gb+ DIMMs: %s\n",
+ drm_dbg_kms(display->drm, "16Gb+ DIMMs: %s\n",
str_yes_no(dram_info->has_16gb_dimms));
return 0;
}
static enum intel_dram_type
-skl_get_dram_type(struct drm_i915_private *i915)
+skl_get_dram_type(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
u32 val;
val = intel_uncore_read(&i915->uncore,
@@ -469,13 +552,13 @@ skl_get_dram_type(struct drm_i915_private *i915)
}
static int
-skl_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+skl_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
int ret;
- dram_info->type = skl_get_dram_type(i915);
+ dram_info->type = skl_get_dram_type(display);
- ret = skl_dram_get_channels_info(i915, dram_info);
+ ret = skl_dram_get_channels_info(display, dram_info);
if (ret)
return ret;
@@ -560,8 +643,9 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val)
dimm->size = bxt_get_dimm_size(val) * intel_dimm_num_devices(dimm);
}
-static int bxt_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+static int bxt_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
u32 val;
u8 valid_ranks = 0;
int i;
@@ -582,11 +666,11 @@ static int bxt_get_dram_info(struct drm_i915_private *i915, struct dram_info *dr
bxt_get_dimm_info(&dimm, val);
type = bxt_get_dimm_type(val);
- drm_WARN_ON(&i915->drm, type != INTEL_DRAM_UNKNOWN &&
+ drm_WARN_ON(display->drm, type != INTEL_DRAM_UNKNOWN &&
dram_info->type != INTEL_DRAM_UNKNOWN &&
dram_info->type != type);
- drm_dbg_kms(&i915->drm,
+ drm_dbg_kms(display->drm,
"CH%u DIMM size: %u Gb, width: X%u, ranks: %u\n",
i - BXT_D_CR_DRP0_DUNIT_START,
dimm.size, dimm.width, dimm.ranks);
@@ -599,25 +683,25 @@ static int bxt_get_dram_info(struct drm_i915_private *i915, struct dram_info *dr
}
if (dram_info->type == INTEL_DRAM_UNKNOWN || valid_ranks == 0) {
- drm_info(&i915->drm, "couldn't get memory information\n");
+ drm_info(display->drm, "couldn't get memory information\n");
return -EINVAL;
}
return 0;
}
-static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv,
+static int icl_pcode_read_mem_global_info(struct intel_display *display,
struct dram_info *dram_info)
{
u32 val = 0;
int ret;
- ret = intel_pcode_read(&dev_priv->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
+ ret = intel_pcode_read(display->drm, ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, &val, NULL);
if (ret)
return ret;
- if (GRAPHICS_VER(dev_priv) == 12) {
+ if (DISPLAY_VER(display) >= 12) {
switch (val & 0xf) {
case 0:
dram_info->type = INTEL_DRAM_DDR4;
@@ -668,25 +752,25 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv,
return 0;
}
-static int gen11_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+static int gen11_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
int ret;
- ret = skl_dram_get_channels_info(i915, dram_info);
+ ret = skl_dram_get_channels_info(display, dram_info);
if (ret)
return ret;
- return icl_pcode_read_mem_global_info(i915, dram_info);
+ return icl_pcode_read_mem_global_info(display, dram_info);
}
-static int gen12_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+static int gen12_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
- return icl_pcode_read_mem_global_info(i915, dram_info);
+ return icl_pcode_read_mem_global_info(display, dram_info);
}
-static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info)
+static int xelpdp_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
{
- struct intel_display *display = i915->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
u32 val = intel_uncore_read(&i915->uncore, MTL_MEM_SS_INFO_GLOBAL);
switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) {
@@ -709,11 +793,11 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info
dram_info->type = INTEL_DRAM_LPDDR3;
break;
case 8:
- drm_WARN_ON(&i915->drm, !IS_DGFX(i915));
+ drm_WARN_ON(display->drm, !display->platform.dgfx);
dram_info->type = INTEL_DRAM_GDDR;
break;
case 9:
- drm_WARN_ON(&i915->drm, !IS_DGFX(i915));
+ drm_WARN_ON(display->drm, !display->platform.dgfx);
dram_info->type = INTEL_DRAM_GDDR_ECC;
break;
default:
@@ -731,41 +815,40 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info
return 0;
}
-int intel_dram_detect(struct drm_i915_private *i915)
+int intel_dram_detect(struct intel_display *display)
{
- struct intel_display *display = i915->display;
struct dram_info *dram_info;
int ret;
- if (IS_DG2(i915) || !intel_display_device_present(display))
+ if (display->platform.dg2 || !HAS_DISPLAY(display))
return 0;
- dram_info = drmm_kzalloc(&i915->drm, sizeof(*dram_info), GFP_KERNEL);
+ dram_info = drmm_kzalloc(display->drm, sizeof(*dram_info), GFP_KERNEL);
if (!dram_info)
return -ENOMEM;
- i915->dram_info = dram_info;
+ display->dram.info = dram_info;
if (DISPLAY_VER(display) >= 14)
- ret = xelpdp_get_dram_info(i915, dram_info);
- else if (GRAPHICS_VER(i915) >= 12)
- ret = gen12_get_dram_info(i915, dram_info);
- else if (GRAPHICS_VER(i915) >= 11)
- ret = gen11_get_dram_info(i915, dram_info);
- else if (IS_BROXTON(i915) || IS_GEMINILAKE(i915))
- ret = bxt_get_dram_info(i915, dram_info);
- else if (GRAPHICS_VER(i915) >= 9)
- ret = skl_get_dram_info(i915, dram_info);
+ ret = xelpdp_get_dram_info(display, dram_info);
+ else if (DISPLAY_VER(display) >= 12)
+ ret = gen12_get_dram_info(display, dram_info);
+ else if (DISPLAY_VER(display) >= 11)
+ ret = gen11_get_dram_info(display, dram_info);
+ else if (display->platform.broxton || display->platform.geminilake)
+ ret = bxt_get_dram_info(display, dram_info);
+ else if (DISPLAY_VER(display) >= 9)
+ ret = skl_get_dram_info(display, dram_info);
else
- ret = i915_get_dram_info(i915, dram_info);
+ ret = i915_get_dram_info(display, dram_info);
- drm_dbg_kms(&i915->drm, "DRAM type: %s\n",
+ drm_dbg_kms(display->drm, "DRAM type: %s\n",
intel_dram_type_str(dram_info->type));
- drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels);
+ drm_dbg_kms(display->drm, "DRAM channels: %u\n", dram_info->num_channels);
- drm_dbg_kms(&i915->drm, "Num QGV points %u\n", dram_info->num_qgv_points);
- drm_dbg_kms(&i915->drm, "Num PSF GV points %u\n", dram_info->num_psf_gv_points);
+ drm_dbg_kms(display->drm, "Num QGV points %u\n", dram_info->num_qgv_points);
+ drm_dbg_kms(display->drm, "Num PSF GV points %u\n", dram_info->num_psf_gv_points);
/* TODO: Do we want to abort probe on dram detection failures? */
if (ret)
@@ -779,45 +862,7 @@ int intel_dram_detect(struct drm_i915_private *i915)
* checks, and prefer not dereferencing on platforms that shouldn't look at dram
* info, to catch accidental and incorrect dram info checks.
*/
-const struct dram_info *intel_dram_info(struct drm_device *drm)
+const struct dram_info *intel_dram_info(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(drm);
-
- return i915->dram_info;
-}
-
-static u32 gen9_edram_size_mb(struct drm_i915_private *i915, u32 cap)
-{
- static const u8 ways[8] = { 4, 8, 12, 16, 16, 16, 16, 16 };
- static const u8 sets[4] = { 1, 1, 2, 2 };
-
- return EDRAM_NUM_BANKS(cap) *
- ways[EDRAM_WAYS_IDX(cap)] *
- sets[EDRAM_SETS_IDX(cap)];
-}
-
-void intel_dram_edram_detect(struct drm_i915_private *i915)
-{
- u32 edram_cap = 0;
-
- if (!(IS_HASWELL(i915) || IS_BROADWELL(i915) || GRAPHICS_VER(i915) >= 9))
- return;
-
- edram_cap = intel_uncore_read_fw(&i915->uncore, HSW_EDRAM_CAP);
-
- /* NB: We can't write IDICR yet because we don't have gt funcs set up */
-
- if (!(edram_cap & EDRAM_ENABLED))
- return;
-
- /*
- * The needed capability bits for size calculation are not there with
- * pre gen9 so return 128MB always.
- */
- if (GRAPHICS_VER(i915) < 9)
- i915->edram_size_mb = 128;
- else
- i915->edram_size_mb = gen9_edram_size_mb(i915, edram_cap);
-
- drm_info(&i915->drm, "Found %uMB of eDRAM\n", i915->edram_size_mb);
+ return display->dram.info;
}
diff --git a/drivers/gpu/drm/i915/soc/intel_dram.h b/drivers/gpu/drm/i915/display/intel_dram.h
index 8475ee379daa..5800b7b4e614 100644
--- a/drivers/gpu/drm/i915/soc/intel_dram.h
+++ b/drivers/gpu/drm/i915/display/intel_dram.h
@@ -8,8 +8,7 @@
#include <linux/types.h>
-struct drm_i915_private;
-struct drm_device;
+struct intel_display;
struct dram_info {
enum intel_dram_type {
@@ -35,11 +34,10 @@ struct dram_info {
bool has_16gb_dimms;
};
-void intel_dram_edram_detect(struct drm_i915_private *i915);
-int intel_dram_detect(struct drm_i915_private *i915);
-unsigned int intel_fsb_freq(struct drm_i915_private *i915);
-unsigned int intel_mem_freq(struct drm_i915_private *i915);
-const struct dram_info *intel_dram_info(struct drm_device *drm);
+int intel_dram_detect(struct intel_display *display);
+unsigned int intel_fsb_freq(struct intel_display *display);
+unsigned int intel_mem_freq(struct intel_display *display);
+const struct dram_info *intel_dram_info(struct intel_display *display);
const char *intel_dram_type_str(enum intel_dram_type type);
#endif /* __INTEL_DRAM_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
index 4ad4efbf9253..ec2a3fb171ab 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -26,7 +26,7 @@
struct intel_dsb {
enum intel_dsb_id id;
- struct intel_dsb_buffer dsb_buf;
+ struct intel_dsb_buffer *dsb_buf;
struct intel_crtc *crtc;
/*
@@ -211,10 +211,10 @@ static void intel_dsb_dump(struct intel_dsb *dsb)
for (i = 0; i < ALIGN(dsb->free_pos, 64 / 4); i += 4)
drm_dbg_kms(display->drm,
" 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4,
- intel_dsb_buffer_read(&dsb->dsb_buf, i),
- intel_dsb_buffer_read(&dsb->dsb_buf, i + 1),
- intel_dsb_buffer_read(&dsb->dsb_buf, i + 2),
- intel_dsb_buffer_read(&dsb->dsb_buf, i + 3));
+ intel_dsb_buffer_read(dsb->dsb_buf, i),
+ intel_dsb_buffer_read(dsb->dsb_buf, i + 1),
+ intel_dsb_buffer_read(dsb->dsb_buf, i + 2),
+ intel_dsb_buffer_read(dsb->dsb_buf, i + 3));
drm_dbg_kms(display->drm, "}\n");
}
@@ -231,12 +231,12 @@ unsigned int intel_dsb_size(struct intel_dsb *dsb)
unsigned int intel_dsb_head(struct intel_dsb *dsb)
{
- return intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf);
+ return intel_dsb_buffer_ggtt_offset(dsb->dsb_buf);
}
static unsigned int intel_dsb_tail(struct intel_dsb *dsb)
{
- return intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf) + intel_dsb_size(dsb);
+ return intel_dsb_buffer_ggtt_offset(dsb->dsb_buf) + intel_dsb_size(dsb);
}
static void intel_dsb_ins_align(struct intel_dsb *dsb)
@@ -263,8 +263,8 @@ static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw)
dsb->ins[0] = ldw;
dsb->ins[1] = udw;
- intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, dsb->ins[0]);
- intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, dsb->ins[1]);
+ intel_dsb_buffer_write(dsb->dsb_buf, dsb->free_pos++, dsb->ins[0]);
+ intel_dsb_buffer_write(dsb->dsb_buf, dsb->free_pos++, dsb->ins[1]);
}
static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb,
@@ -335,13 +335,13 @@ void intel_dsb_reg_write_indexed(struct intel_dsb *dsb,
/* Update the count */
dsb->ins[0]++;
- intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset + 0,
+ intel_dsb_buffer_write(dsb->dsb_buf, dsb->ins_start_offset + 0,
dsb->ins[0]);
- intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, val);
+ intel_dsb_buffer_write(dsb->dsb_buf, dsb->free_pos++, val);
/* if number of data words is odd, then the last dword should be 0.*/
if (dsb->free_pos & 0x1)
- intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos, 0);
+ intel_dsb_buffer_write(dsb->dsb_buf, dsb->free_pos, 0);
}
void intel_dsb_reg_write(struct intel_dsb *dsb,
@@ -521,7 +521,7 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb)
aligned_tail = ALIGN(tail, CACHELINE_BYTES);
if (aligned_tail > tail)
- intel_dsb_buffer_memset(&dsb->dsb_buf, dsb->free_pos, 0,
+ intel_dsb_buffer_memset(dsb->dsb_buf, dsb->free_pos, 0,
aligned_tail - tail);
dsb->free_pos = aligned_tail / 4;
@@ -541,7 +541,7 @@ static void intel_dsb_gosub_align(struct intel_dsb *dsb)
* "Ensure GOSUB is not placed in cacheline QW slot 6 or 7 (numbered 0-7)"
*/
if (aligned_tail - tail <= 2 * 8)
- intel_dsb_buffer_memset(&dsb->dsb_buf, dsb->free_pos, 0,
+ intel_dsb_buffer_memset(dsb->dsb_buf, dsb->free_pos, 0,
aligned_tail - tail);
dsb->free_pos = aligned_tail / 4;
@@ -606,14 +606,14 @@ void intel_dsb_gosub_finish(struct intel_dsb *dsb)
*/
intel_dsb_noop(dsb, 8);
- intel_dsb_buffer_flush_map(&dsb->dsb_buf);
+ intel_dsb_buffer_flush_map(dsb->dsb_buf);
}
void intel_dsb_finish(struct intel_dsb *dsb)
{
intel_dsb_align_tail(dsb);
- intel_dsb_buffer_flush_map(&dsb->dsb_buf);
+ intel_dsb_buffer_flush_map(dsb->dsb_buf);
}
static u32 dsb_error_int_status(struct intel_display *display)
@@ -888,7 +888,7 @@ void intel_dsb_wait(struct intel_dsb *dsb)
!is_busy,
100, 1000, false);
if (ret) {
- u32 offset = intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf);
+ u32 offset = intel_dsb_buffer_ggtt_offset(dsb->dsb_buf);
intel_de_write_fw(display, DSB_CTRL(pipe, dsb->id),
DSB_ENABLE | DSB_HALT);
@@ -934,6 +934,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state,
unsigned int max_cmds)
{
struct intel_display *display = to_intel_display(state);
+ struct intel_dsb_buffer *dsb_buf;
struct ref_tracker *wakeref;
struct intel_dsb *dsb;
unsigned int size;
@@ -953,9 +954,12 @@ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state,
/* ~1 qword per instruction, full cachelines */
size = ALIGN(max_cmds * 8, CACHELINE_BYTES);
- if (!intel_dsb_buffer_create(crtc, &dsb->dsb_buf, size))
+ dsb_buf = intel_dsb_buffer_create(display->drm, size);
+ if (IS_ERR(dsb_buf))
goto out_put_rpm;
+ dsb->dsb_buf = dsb_buf;
+
intel_display_rpm_put(display, wakeref);
dsb->id = dsb_id;
@@ -988,7 +992,7 @@ out:
*/
void intel_dsb_cleanup(struct intel_dsb *dsb)
{
- intel_dsb_buffer_cleanup(&dsb->dsb_buf);
+ intel_dsb_buffer_cleanup(dsb->dsb_buf);
kfree(dsb);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.c b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c
index c77d48bda26a..50faf3869b6c 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb_buffer.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c
@@ -7,9 +7,14 @@
#include "gem/i915_gem_lmem.h"
#include "i915_drv.h"
#include "i915_vma.h"
-#include "intel_display_types.h"
#include "intel_dsb_buffer.h"
+struct intel_dsb_buffer {
+ u32 *cmd_buf;
+ struct i915_vma *vma;
+ size_t buf_size;
+};
+
u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf)
{
return i915_ggtt_offset(dsb_buf->vma);
@@ -32,48 +37,66 @@ void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val,
memset(&dsb_buf->cmd_buf[idx], val, size);
}
-bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, size_t size)
+struct intel_dsb_buffer *intel_dsb_buffer_create(struct drm_device *drm, size_t size)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct intel_dsb_buffer *dsb_buf;
struct drm_i915_gem_object *obj;
struct i915_vma *vma;
u32 *buf;
+ int ret;
+
+ dsb_buf = kzalloc(sizeof(*dsb_buf), GFP_KERNEL);
+ if (!dsb_buf)
+ return ERR_PTR(-ENOMEM);
if (HAS_LMEM(i915)) {
obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size),
I915_BO_ALLOC_CONTIGUOUS);
- if (IS_ERR(obj))
- return false;
+ if (IS_ERR(obj)) {
+ ret = PTR_ERR(obj);
+ goto err;
+ }
} else {
obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size));
- if (IS_ERR(obj))
- return false;
+ if (IS_ERR(obj)) {
+ ret = PTR_ERR(obj);
+ goto err;
+ }
i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE);
}
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
i915_gem_object_put(obj);
- return false;
+ goto err;
}
buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
- return false;
+ goto err;
}
dsb_buf->vma = vma;
dsb_buf->cmd_buf = buf;
dsb_buf->buf_size = size;
- return true;
+ return dsb_buf;
+
+err:
+ kfree(dsb_buf);
+
+ return ERR_PTR(ret);
}
void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf)
{
i915_vma_unpin_and_release(&dsb_buf->vma, I915_VMA_RELEASE_MAP);
+ kfree(dsb_buf);
}
void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf)
diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h
index 425acd393905..d746c872e0c7 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h
+++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h
@@ -8,21 +8,14 @@
#include <linux/types.h>
-struct intel_crtc;
-struct i915_vma;
-
-struct intel_dsb_buffer {
- u32 *cmd_buf;
- struct i915_vma *vma;
- size_t buf_size;
-};
+struct drm_device;
+struct intel_dsb_buffer;
u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf);
void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val);
u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx);
void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size);
-bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf,
- size_t size);
+struct intel_dsb_buffer *intel_dsb_buffer_create(struct drm_device *drm, size_t size);
void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf);
void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf);
diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h
index 89c7166a3860..489d26ffd235 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi.h
+++ b/drivers/gpu/drm/i915/display/intel_dsi.h
@@ -29,6 +29,9 @@
#include "intel_display_types.h"
+struct intel_dsi_host;
+struct ref_tracker;
+
#define INTEL_DSI_VIDEO_MODE 0
#define INTEL_DSI_COMMAND_MODE 1
@@ -37,13 +40,11 @@
#define DSI_DUAL_LINK_FRONT_BACK 1
#define DSI_DUAL_LINK_PIXEL_ALT 2
-struct intel_dsi_host;
-
struct intel_dsi {
struct intel_encoder base;
struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
- intel_wakeref_t io_wakeref[I915_MAX_PORTS];
+ struct ref_tracker *io_wakeref[I915_MAX_PORTS];
/* GPIO Desc for panel and backlight control */
struct gpio_desc *gpio_panel;
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index b34b4961fe1c..b9bd9b6dfe94 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fb.c
@@ -20,7 +20,7 @@
#include "intel_fb.h"
#include "intel_fb_bo.h"
#include "intel_frontbuffer.h"
-#include "intel_panic.h"
+#include "intel_parent.h"
#include "intel_plane.h"
#define check_array_bounds(display, a, i) drm_WARN_ON((display)->drm, (i) >= ARRAY_SIZE(a))
@@ -558,7 +558,7 @@ static bool plane_has_modifier(struct intel_display *display,
* where supported.
*/
if (intel_fb_is_ccs_modifier(md->modifier) &&
- HAS_AUX_CCS(display) != !!md->ccs.packed_aux_planes)
+ intel_parent_has_auxccs(display) != !!md->ccs.packed_aux_planes)
return false;
if (md->modifier == I915_FORMAT_MOD_4_TILED_BMG_CCS &&
@@ -2216,7 +2216,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
int ret;
int i;
- intel_fb->panic = intel_panic_alloc();
+ intel_fb->panic = intel_parent_panic_alloc(display);
if (!intel_fb->panic)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 437d2fda20a7..fef2f35ff1e9 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -45,12 +45,6 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
-#include "gem/i915_gem_stolen.h"
-
-#include "gt/intel_gt_types.h"
-
-#include "i915_drv.h"
-#include "i915_vgpu.h"
#include "i915_vma.h"
#include "i9xx_plane_regs.h"
#include "intel_de.h"
@@ -64,6 +58,8 @@
#include "intel_fbc.h"
#include "intel_fbc_regs.h"
#include "intel_frontbuffer.h"
+#include "intel_parent.h"
+#include "intel_step.h"
#define for_each_fbc_id(__display, __fbc_id) \
for ((__fbc_id) = INTEL_FBC_A; (__fbc_id) < I915_MAX_FBCS; (__fbc_id)++) \
@@ -71,7 +67,9 @@
#define for_each_intel_fbc(__display, __fbc, __fbc_id) \
for_each_fbc_id((__display), (__fbc_id)) \
- for_each_if((__fbc) = (__display)->fbc[(__fbc_id)])
+ for_each_if((__fbc) = (__display)->fbc.instances[(__fbc_id)])
+
+#define FBC_SYS_CACHE_ID_NONE I915_MAX_FBCS
struct intel_fbc_funcs {
void (*activate)(struct intel_fbc *fbc);
@@ -129,6 +127,19 @@ struct intel_fbc {
const char *no_fbc_reason;
};
+static struct intel_fbc *intel_fbc_for_pipe(struct intel_display *display, enum pipe pipe)
+{
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
+ struct intel_plane *primary = NULL;
+
+ primary = to_intel_plane(crtc->base.primary);
+
+ if (drm_WARN_ON(display->drm, !primary))
+ return NULL;
+
+ return primary->fbc;
+}
+
/* plane stride in pixels */
static unsigned int intel_fbc_plane_stride(const struct intel_plane_state *plane_state)
{
@@ -204,7 +215,7 @@ static unsigned int _intel_fbc_cfb_stride(struct intel_display *display,
static unsigned int intel_fbc_cfb_stride(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
unsigned int stride = intel_fbc_plane_cfb_stride(plane_state);
unsigned int width = drm_rect_width(&plane_state->uapi.src) >> 16;
unsigned int cpp = intel_fbc_cfb_cpp(plane_state);
@@ -235,7 +246,7 @@ static unsigned int _intel_fbc_cfb_size(struct intel_display *display,
static unsigned int intel_fbc_cfb_size(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
unsigned int height = drm_rect_height(&plane_state->uapi.src) >> 16;
return _intel_fbc_cfb_size(display, height, intel_fbc_cfb_stride(plane_state));
@@ -243,7 +254,7 @@ static unsigned int intel_fbc_cfb_size(const struct intel_plane_state *plane_sta
static u16 intel_fbc_override_cfb_stride(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
unsigned int stride_aligned = intel_fbc_cfb_stride(plane_state);
unsigned int stride = intel_fbc_plane_cfb_stride(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
@@ -267,9 +278,7 @@ static u16 intel_fbc_override_cfb_stride(const struct intel_plane_state *plane_s
static bool intel_fbc_has_fences(struct intel_display *display)
{
- struct drm_i915_private __maybe_unused *i915 = to_i915(display->drm);
-
- return intel_gt_support_legacy_fencing(to_gt(i915));
+ return intel_parent_has_fenced_regions(display);
}
static u32 i8xx_fbc_ctl(struct intel_fbc *fbc)
@@ -382,17 +391,17 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)
struct intel_display *display = fbc->display;
drm_WARN_ON(display->drm,
- range_end_overflows_t(u64, i915_gem_stolen_area_address(display->drm),
- i915_gem_stolen_node_offset(fbc->compressed_fb),
+ range_end_overflows_t(u64, intel_parent_stolen_area_address(display),
+ intel_parent_stolen_node_offset(display, fbc->compressed_fb),
U32_MAX));
drm_WARN_ON(display->drm,
- range_end_overflows_t(u64, i915_gem_stolen_area_address(display->drm),
- i915_gem_stolen_node_offset(fbc->compressed_llb),
+ range_end_overflows_t(u64, intel_parent_stolen_area_address(display),
+ intel_parent_stolen_node_offset(display, fbc->compressed_llb),
U32_MAX));
intel_de_write(display, FBC_CFB_BASE,
- i915_gem_stolen_node_address(fbc->compressed_fb));
+ intel_parent_stolen_node_address(display, fbc->compressed_fb));
intel_de_write(display, FBC_LL_BASE,
- i915_gem_stolen_node_address(fbc->compressed_llb));
+ intel_parent_stolen_node_address(display, fbc->compressed_llb));
}
static const struct intel_fbc_funcs i8xx_fbc_funcs = {
@@ -500,7 +509,7 @@ static void g4x_fbc_program_cfb(struct intel_fbc *fbc)
struct intel_display *display = fbc->display;
intel_de_write(display, DPFC_CB_BASE,
- i915_gem_stolen_node_offset(fbc->compressed_fb));
+ intel_parent_stolen_node_offset(display, fbc->compressed_fb));
}
static const struct intel_fbc_funcs g4x_fbc_funcs = {
@@ -569,7 +578,7 @@ static void ilk_fbc_program_cfb(struct intel_fbc *fbc)
struct intel_display *display = fbc->display;
intel_de_write(display, ILK_DPFC_CB_BASE(fbc->id),
- i915_gem_stolen_node_offset(fbc->compressed_fb));
+ intel_parent_stolen_node_offset(display, fbc->compressed_fb));
}
static const struct intel_fbc_funcs ilk_fbc_funcs = {
@@ -808,7 +817,7 @@ static u64 intel_fbc_stolen_end(struct intel_display *display)
* underruns, even if that range is not reserved by the BIOS. */
if (display->platform.broadwell ||
(DISPLAY_VER(display) == 9 && !display->platform.broxton))
- end = i915_gem_stolen_area_size(display->drm) - 8 * 1024 * 1024;
+ end = intel_parent_stolen_area_size(display) - 8 * 1024 * 1024;
else
end = U64_MAX;
@@ -843,14 +852,14 @@ static int find_compression_limit(struct intel_fbc *fbc,
size /= limit;
/* Try to over-allocate to reduce reallocations and fragmentation. */
- ret = i915_gem_stolen_insert_node_in_range(fbc->compressed_fb,
- size <<= 1, 4096, 0, end);
+ ret = intel_parent_stolen_insert_node_in_range(display, fbc->compressed_fb,
+ size <<= 1, 4096, 0, end);
if (ret == 0)
return limit;
for (; limit <= intel_fbc_max_limit(display); limit <<= 1) {
- ret = i915_gem_stolen_insert_node_in_range(fbc->compressed_fb,
- size >>= 1, 4096, 0, end);
+ ret = intel_parent_stolen_insert_node_in_range(display, fbc->compressed_fb,
+ size >>= 1, 4096, 0, end);
if (ret == 0)
return limit;
}
@@ -865,12 +874,12 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc,
int ret;
drm_WARN_ON(display->drm,
- i915_gem_stolen_node_allocated(fbc->compressed_fb));
+ intel_parent_stolen_node_allocated(display, fbc->compressed_fb));
drm_WARN_ON(display->drm,
- i915_gem_stolen_node_allocated(fbc->compressed_llb));
+ intel_parent_stolen_node_allocated(display, fbc->compressed_llb));
if (DISPLAY_VER(display) < 5 && !display->platform.g4x) {
- ret = i915_gem_stolen_insert_node(fbc->compressed_llb, 4096, 4096);
+ ret = intel_parent_stolen_insert_node(display, fbc->compressed_llb, 4096, 4096);
if (ret)
goto err;
}
@@ -886,14 +895,14 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc,
drm_dbg_kms(display->drm,
"reserved %llu bytes of contiguous stolen space for FBC, limit: %d\n",
- i915_gem_stolen_node_size(fbc->compressed_fb), fbc->limit);
+ intel_parent_stolen_node_size(display, fbc->compressed_fb), fbc->limit);
return 0;
err_llb:
- if (i915_gem_stolen_node_allocated(fbc->compressed_llb))
- i915_gem_stolen_remove_node(fbc->compressed_llb);
+ if (intel_parent_stolen_node_allocated(display, fbc->compressed_llb))
+ intel_parent_stolen_remove_node(display, fbc->compressed_llb);
err:
- if (i915_gem_stolen_initialized(display->drm))
+ if (intel_parent_stolen_initialized(display))
drm_info_once(display->drm,
"not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size);
return -ENOSPC;
@@ -945,15 +954,83 @@ static void intel_fbc_program_workarounds(struct intel_fbc *fbc)
fbc_compressor_clkgate_disable_wa(fbc, true);
}
+static void fbc_sys_cache_update_config(struct intel_display *display, u32 reg,
+ enum intel_fbc_id id)
+{
+ if (!HAS_FBC_SYS_CACHE(display))
+ return;
+
+ lockdep_assert_held(&display->fbc.sys_cache.lock);
+
+ /*
+ * Wa_14025769978:
+ * Fixes: SoC hardware issue in read caching
+ * Workaround: disable cache read setting which is enabled by default.
+ */
+ if (!intel_display_wa(display, 14025769978))
+ /* Cache read enable is set by default */
+ reg |= FBC_SYS_CACHE_READ_ENABLE;
+
+ intel_de_write(display, XE3P_LPD_FBC_SYS_CACHE_USAGE_CFG, reg);
+
+ display->fbc.sys_cache.id = id;
+}
+
+static void fbc_sys_cache_disable(const struct intel_fbc *fbc)
+{
+ struct intel_display *display = fbc->display;
+ struct sys_cache_cfg *sys_cache = &display->fbc.sys_cache;
+
+ mutex_lock(&sys_cache->lock);
+ /* clear only if "fbc" reserved the cache */
+ if (sys_cache->id == fbc->id)
+ fbc_sys_cache_update_config(display, 0, FBC_SYS_CACHE_ID_NONE);
+ mutex_unlock(&sys_cache->lock);
+}
+
+static int fbc_sys_cache_limit(struct intel_display *display)
+{
+ if (DISPLAY_VER(display) == 35)
+ return 2 * 1024 * 1024;
+
+ return 0;
+}
+
+static void fbc_sys_cache_enable(const struct intel_fbc *fbc)
+{
+ struct intel_display *display = fbc->display;
+ struct sys_cache_cfg *sys_cache = &display->fbc.sys_cache;
+ int range, offset;
+ u32 cfg;
+
+ if (!HAS_FBC_SYS_CACHE(display))
+ return;
+
+ range = fbc_sys_cache_limit(display) / (64 * 1024);
+
+ offset = intel_parent_stolen_node_offset(display, fbc->compressed_fb) / (4 * 1024);
+
+ cfg = FBC_SYS_CACHE_TAG_USE_RES_SPACE | FBC_SYS_CACHEABLE_RANGE(range) |
+ FBC_SYS_CACHE_START_BASE(offset);
+
+ mutex_lock(&sys_cache->lock);
+ /* update sys cache config only if sys cache is unassigned */
+ if (sys_cache->id == FBC_SYS_CACHE_ID_NONE)
+ fbc_sys_cache_update_config(display, cfg, fbc->id);
+ mutex_unlock(&sys_cache->lock);
+}
+
static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc)
{
+ struct intel_display *display = fbc->display;
+
if (WARN_ON(intel_fbc_hw_is_active(fbc)))
return;
- if (i915_gem_stolen_node_allocated(fbc->compressed_llb))
- i915_gem_stolen_remove_node(fbc->compressed_llb);
- if (i915_gem_stolen_node_allocated(fbc->compressed_fb))
- i915_gem_stolen_remove_node(fbc->compressed_fb);
+ if (intel_parent_stolen_node_allocated(display, fbc->compressed_llb))
+ intel_parent_stolen_remove_node(display, fbc->compressed_llb);
+ if (intel_parent_stolen_node_allocated(display, fbc->compressed_fb))
+ intel_parent_stolen_remove_node(display, fbc->compressed_fb);
}
void intel_fbc_cleanup(struct intel_display *display)
@@ -966,11 +1043,16 @@ void intel_fbc_cleanup(struct intel_display *display)
__intel_fbc_cleanup_cfb(fbc);
mutex_unlock(&fbc->lock);
- i915_gem_stolen_node_free(fbc->compressed_fb);
- i915_gem_stolen_node_free(fbc->compressed_llb);
+ intel_parent_stolen_node_free(display, fbc->compressed_fb);
+ intel_parent_stolen_node_free(display, fbc->compressed_llb);
kfree(fbc);
}
+
+ mutex_lock(&display->fbc.sys_cache.lock);
+ drm_WARN_ON(display->drm,
+ display->fbc.sys_cache.id != FBC_SYS_CACHE_ID_NONE);
+ mutex_unlock(&display->fbc.sys_cache.lock);
}
static bool i8xx_fbc_stride_is_valid(const struct intel_plane_state *plane_state)
@@ -1016,7 +1098,7 @@ static bool icl_fbc_stride_is_valid(const struct intel_plane_state *plane_state)
static bool stride_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
if (DISPLAY_VER(display) >= 11)
return icl_fbc_stride_is_valid(plane_state);
@@ -1032,7 +1114,7 @@ static bool stride_is_valid(const struct intel_plane_state *plane_state)
static bool i8xx_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
switch (fb->format->format) {
@@ -1052,7 +1134,7 @@ static bool i8xx_fbc_pixel_format_is_valid(const struct intel_plane_state *plane
static bool g4x_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
switch (fb->format->format) {
@@ -1131,7 +1213,7 @@ intel_fbc_is_enable_pixel_normalizer(const struct intel_plane_state *plane_state
static bool pixel_format_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
if (DISPLAY_VER(display) >= 35)
return xe3p_lpd_fbc_pixel_format_is_valid(plane_state);
@@ -1167,7 +1249,7 @@ static bool skl_fbc_rotation_is_valid(const struct intel_plane_state *plane_stat
static bool rotation_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
if (DISPLAY_VER(display) >= 9)
return skl_fbc_rotation_is_valid(plane_state);
@@ -1206,7 +1288,7 @@ static void intel_fbc_max_surface_size(struct intel_display *display,
*/
static bool intel_fbc_surface_size_ok(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
unsigned int effective_w, effective_h, max_w, max_h;
intel_fbc_max_surface_size(display, &max_w, &max_h);
@@ -1239,7 +1321,7 @@ static void intel_fbc_max_plane_size(struct intel_display *display,
static bool intel_fbc_plane_size_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
unsigned int w, h, max_w, max_h;
intel_fbc_max_plane_size(display, &max_w, &max_h);
@@ -1264,7 +1346,7 @@ static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state)
static bool tiling_is_valid(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
if (DISPLAY_VER(display) >= 9)
return skl_fbc_tiling_valid(plane_state);
@@ -1344,7 +1426,7 @@ static void intel_fbc_update_state(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_plane *plane)
{
- struct intel_display *display = to_intel_display(state->base.dev);
+ struct intel_display *display = to_intel_display(state);
const struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
const struct intel_plane_state *plane_state =
@@ -1377,7 +1459,7 @@ static void intel_fbc_update_state(struct intel_atomic_state *state,
static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state)
{
- struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);
+ struct intel_display *display = to_intel_display(plane_state);
/*
* The use of a CPU fence is one of two ways to detect writes by the
@@ -1398,12 +1480,13 @@ static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state)
static bool intel_fbc_is_cfb_ok(const struct intel_plane_state *plane_state)
{
+ struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct intel_fbc *fbc = plane->fbc;
return intel_fbc_min_limit(plane_state) <= fbc->limit &&
intel_fbc_cfb_size(plane_state) <= fbc->limit *
- i915_gem_stolen_node_size(fbc->compressed_fb);
+ intel_parent_stolen_node_size(display, fbc->compressed_fb);
}
static bool intel_fbc_is_ok(const struct intel_plane_state *plane_state)
@@ -1484,8 +1567,7 @@ static int _intel_fbc_min_cdclk(const struct intel_crtc_state *crtc_state)
static int intel_fbc_check_plane(struct intel_atomic_state *state,
struct intel_plane *plane)
{
- struct intel_display *display = to_intel_display(state->base.dev);
- struct drm_i915_private *i915 = to_i915(display->drm);
+ struct intel_display *display = to_intel_display(state);
struct intel_plane_state *plane_state =
intel_atomic_get_new_plane_state(state, plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
@@ -1496,12 +1578,12 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
if (!fbc)
return 0;
- if (!i915_gem_stolen_initialized(display->drm)) {
+ if (!intel_parent_stolen_initialized(display)) {
plane_state->no_fbc_reason = "stolen memory not initialised";
return 0;
}
- if (intel_vgpu_active(i915)) {
+ if (intel_parent_vgpu_active(display)) {
plane_state->no_fbc_reason = "VGPU active";
return 0;
}
@@ -1521,6 +1603,16 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
return 0;
}
+ /*
+ * Wa_15018326506:
+ * Fixes: Underrun during media decode
+ * Workaround: Do not enable FBC
+ */
+ if (intel_display_wa(display, 15018326506)) {
+ plane_state->no_fbc_reason = "Wa_15018326506";
+ return 0;
+ }
+
/* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */
if (intel_display_vtd_active(display) &&
(display->platform.skylake || display->platform.broxton)) {
@@ -1702,7 +1794,7 @@ static bool __intel_fbc_pre_update(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_plane *plane)
{
- struct intel_display *display = to_intel_display(state->base.dev);
+ struct intel_display *display = to_intel_display(state);
struct intel_fbc *fbc = plane->fbc;
bool need_vblank_wait = false;
@@ -1775,6 +1867,8 @@ static void __intel_fbc_disable(struct intel_fbc *fbc)
__intel_fbc_cleanup_cfb(fbc);
+ fbc_sys_cache_disable(fbc);
+
/* wa_18038517565 Enable DPFC clock gating after FBC disable */
if (display->platform.dg2 || DISPLAY_VER(display) >= 14)
fbc_compressor_clkgate_disable_wa(fbc, false);
@@ -1915,7 +2009,7 @@ static void __intel_fbc_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_plane *plane)
{
- struct intel_display *display = to_intel_display(state->base.dev);
+ struct intel_display *display = to_intel_display(state);
const struct intel_plane_state *plane_state =
intel_atomic_get_new_plane_state(state, plane);
struct intel_fbc *fbc = plane->fbc;
@@ -1967,6 +2061,8 @@ static void __intel_fbc_enable(struct intel_atomic_state *state,
intel_fbc_program_workarounds(fbc);
intel_fbc_program_cfb(fbc);
+
+ fbc_sys_cache_enable(fbc);
}
/**
@@ -1977,7 +2073,7 @@ static void __intel_fbc_enable(struct intel_atomic_state *state,
*/
void intel_fbc_disable(struct intel_crtc *crtc)
{
- struct intel_display *display = to_intel_display(crtc->base.dev);
+ struct intel_display *display = to_intel_display(crtc);
struct intel_plane *plane;
for_each_intel_plane(display->drm, plane) {
@@ -2119,6 +2215,37 @@ void intel_fbc_handle_fifo_underrun_irq(struct intel_display *display)
__intel_fbc_handle_fifo_underrun_irq(fbc);
}
+/**
+ * intel_fbc_read_underrun_dbg_info - Read and log FBC-related FIFO underrun debug info
+ * @display: display device instance
+ * @pipe: the pipe possibly containing the FBC
+ * @log: log the info?
+ *
+ * If @pipe does not contain an FBC instance, this function bails early.
+ * Otherwise, FBC-related FIFO underrun is read and cleared, and then, if @log
+ * is true, printed with error level.
+ */
+void intel_fbc_read_underrun_dbg_info(struct intel_display *display,
+ enum pipe pipe, bool log)
+{
+ struct intel_fbc *fbc = intel_fbc_for_pipe(display, pipe);
+ u32 val;
+
+ if (!fbc)
+ return;
+
+ val = intel_de_read(display, FBC_DEBUG_STATUS(fbc->id));
+ if (!(val & FBC_UNDERRUN_DECMPR))
+ return;
+
+ intel_de_write(display, FBC_DEBUG_STATUS(fbc->id), FBC_UNDERRUN_DECMPR);
+
+ if (log)
+ drm_err(display->drm,
+ "Pipe %c FIFO underrun info: FBC decompressing\n",
+ pipe_name(pipe));
+}
+
/*
* The DDX driver changes its behavior depending on the value it reads from
* i915.enable_fbc, so sanitize it by translating the default value into either
@@ -2156,10 +2283,10 @@ static struct intel_fbc *intel_fbc_create(struct intel_display *display,
if (!fbc)
return NULL;
- fbc->compressed_fb = i915_gem_stolen_node_alloc(display->drm);
+ fbc->compressed_fb = intel_parent_stolen_node_alloc(display);
if (!fbc->compressed_fb)
goto err;
- fbc->compressed_llb = i915_gem_stolen_node_alloc(display->drm);
+ fbc->compressed_llb = intel_parent_stolen_node_alloc(display);
if (!fbc->compressed_llb)
goto err;
@@ -2184,8 +2311,8 @@ static struct intel_fbc *intel_fbc_create(struct intel_display *display,
return fbc;
err:
- i915_gem_stolen_node_free(fbc->compressed_llb);
- i915_gem_stolen_node_free(fbc->compressed_fb);
+ intel_parent_stolen_node_free(display, fbc->compressed_llb);
+ intel_parent_stolen_node_free(display, fbc->compressed_fb);
kfree(fbc);
return NULL;
@@ -2206,7 +2333,10 @@ void intel_fbc_init(struct intel_display *display)
display->params.enable_fbc);
for_each_fbc_id(display, fbc_id)
- display->fbc[fbc_id] = intel_fbc_create(display, fbc_id);
+ display->fbc.instances[fbc_id] = intel_fbc_create(display, fbc_id);
+
+ mutex_init(&display->fbc.sys_cache.lock);
+ display->fbc.sys_cache.id = FBC_SYS_CACHE_ID_NONE;
}
/**
@@ -2226,6 +2356,11 @@ void intel_fbc_sanitize(struct intel_display *display)
if (intel_fbc_hw_is_active(fbc))
intel_fbc_hw_deactivate(fbc);
}
+
+ /* Ensure the sys cache usage config is clear as well */
+ mutex_lock(&display->fbc.sys_cache.lock);
+ fbc_sys_cache_update_config(display, 0, FBC_SYS_CACHE_ID_NONE);
+ mutex_unlock(&display->fbc.sys_cache.lock);
}
static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused)
@@ -2244,6 +2379,11 @@ static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused)
seq_puts(m, "FBC enabled\n");
seq_printf(m, "Compressing: %s\n",
str_yes_no(intel_fbc_is_compressing(fbc)));
+
+ mutex_lock(&display->fbc.sys_cache.lock);
+ seq_printf(m, "Using system cache: %s\n",
+ str_yes_no(display->fbc.sys_cache.id == fbc->id));
+ mutex_unlock(&display->fbc.sys_cache.lock);
} else {
seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason);
}
@@ -2325,7 +2465,7 @@ void intel_fbc_debugfs_register(struct intel_display *display)
{
struct intel_fbc *fbc;
- fbc = display->fbc[INTEL_FBC_A];
+ fbc = display->fbc.instances[INTEL_FBC_A];
if (fbc)
intel_fbc_debugfs_add(fbc, display->drm->debugfs_root);
}
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h
index 91424563206a..f0255ddae2b6 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.h
+++ b/drivers/gpu/drm/i915/display/intel_fbc.h
@@ -9,6 +9,7 @@
#include <linux/types.h>
enum fb_op_origin;
+enum pipe;
struct intel_atomic_state;
struct intel_crtc;
struct intel_crtc_state;
@@ -46,6 +47,8 @@ void intel_fbc_flush(struct intel_display *display,
unsigned int frontbuffer_bits, enum fb_op_origin origin);
void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane);
void intel_fbc_handle_fifo_underrun_irq(struct intel_display *display);
+void intel_fbc_read_underrun_dbg_info(struct intel_display *display,
+ enum pipe, bool log);
void intel_fbc_reset_underrun(struct intel_display *display);
void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc);
void intel_fbc_debugfs_register(struct intel_display *display);
diff --git a/drivers/gpu/drm/i915/display/intel_fbc_regs.h b/drivers/gpu/drm/i915/display/intel_fbc_regs.h
index b1d0161a3196..4178e602d7d7 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_fbc_regs.h
@@ -88,6 +88,8 @@
#define DPFC_FENCE_YOFF _MMIO(0x3218)
#define ILK_DPFC_FENCE_YOFF(fbc_id) _MMIO_PIPE((fbc_id), 0x43218, 0x43258)
#define DPFC_CHICKEN _MMIO(0x3224)
+#define FBC_DEBUG_STATUS(fbc_id) _MMIO_PIPE((fbc_id), 0x43220, 0x43260)
+#define FBC_UNDERRUN_DECMPR REG_BIT(27)
#define ILK_DPFC_CHICKEN(fbc_id) _MMIO_PIPE((fbc_id), 0x43224, 0x43264)
#define DPFC_HT_MODIFY REG_BIT(31) /* pre-ivb */
#define DPFC_NUKE_ON_ANY_MODIFICATION REG_BIT(23) /* bdw+ */
@@ -126,4 +128,14 @@
#define FBC_REND_NUKE REG_BIT(2)
#define FBC_REND_CACHE_CLEAN REG_BIT(1)
+#define XE3P_LPD_FBC_SYS_CACHE_USAGE_CFG _MMIO(0x1344E0)
+#define FBC_SYS_CACHE_START_BASE_MASK REG_GENMASK(31, 16)
+#define FBC_SYS_CACHE_START_BASE(base) REG_FIELD_PREP(FBC_SYS_CACHE_START_BASE_MASK, (base))
+#define FBC_SYS_CACHEABLE_RANGE_MASK REG_GENMASK(15, 4)
+#define FBC_SYS_CACHEABLE_RANGE(range) REG_FIELD_PREP(FBC_SYS_CACHEABLE_RANGE_MASK, (range))
+#define FBC_SYS_CACHE_TAG_MASK REG_GENMASK(3, 2)
+#define FBC_SYS_CACHE_TAG_DONT_CACHE REG_FIELD_PREP(FBC_SYS_CACHE_TAG_MASK, 0)
+#define FBC_SYS_CACHE_TAG_USE_RES_SPACE REG_FIELD_PREP(FBC_SYS_CACHE_TAG_MASK, 3)
+#define FBC_SYS_CACHE_READ_ENABLE REG_BIT(0)
+
#endif /* __INTEL_FBC_REGS__ */
diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
index c2ce8461ac9e..b413b3e871d8 100644
--- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
@@ -25,6 +25,8 @@
*
*/
+#include <linux/seq_buf.h>
+
#include <drm/drm_print.h>
#include "i915_reg.h"
@@ -57,6 +59,100 @@
* The code also supports underrun detection on the PCH transcoder.
*/
+#define UNDERRUN_DBG1_NUM_PLANES 6
+
+static void log_underrun_dbg1(struct intel_display *display, enum pipe pipe,
+ unsigned long plane_mask, const char *info)
+{
+ DECLARE_SEQ_BUF(planes_desc, 32);
+ unsigned int i;
+
+ if (!plane_mask)
+ return;
+
+ for_each_set_bit(i, &plane_mask, UNDERRUN_DBG1_NUM_PLANES) {
+ if (i == 0)
+ seq_buf_puts(&planes_desc, "[C]");
+ else
+ seq_buf_printf(&planes_desc, "[%d]", i);
+ }
+
+ drm_err(display->drm, "Pipe %c FIFO underrun info: %s on planes: %s\n",
+ pipe_name(pipe), info, seq_buf_str(&planes_desc));
+
+ drm_WARN_ON(display->drm, seq_buf_has_overflowed(&planes_desc));
+}
+
+static void read_underrun_dbg1(struct intel_display *display, enum pipe pipe, bool log)
+{
+ u32 val = intel_de_read(display, UNDERRUN_DBG1(pipe));
+
+ if (!val)
+ return;
+
+ intel_de_write(display, UNDERRUN_DBG1(pipe), val);
+
+ if (!log)
+ return;
+
+ log_underrun_dbg1(display, pipe, REG_FIELD_GET(UNDERRUN_DBUF_BLOCK_NOT_VALID_MASK, val),
+ "DBUF block not valid");
+ log_underrun_dbg1(display, pipe, REG_FIELD_GET(UNDERRUN_DDB_EMPTY_MASK, val),
+ "DDB empty");
+ log_underrun_dbg1(display, pipe, REG_FIELD_GET(UNDERRUN_DBUF_NOT_FILLED_MASK, val),
+ "DBUF not completely filled");
+ log_underrun_dbg1(display, pipe, REG_FIELD_GET(UNDERRUN_BELOW_WM0_MASK, val),
+ "DBUF below WM0");
+}
+
+static void read_underrun_dbg2(struct intel_display *display, enum pipe pipe, bool log)
+{
+ u32 val = intel_de_read(display, UNDERRUN_DBG2(pipe));
+
+ if (!(val & UNDERRUN_FRAME_LINE_COUNTERS_FROZEN))
+ return;
+
+ intel_de_write(display, UNDERRUN_DBG2(pipe), UNDERRUN_FRAME_LINE_COUNTERS_FROZEN);
+
+ if (log)
+ drm_err(display->drm,
+ "Pipe %c FIFO underrun info: frame count: %u, line count: %u\n",
+ pipe_name(pipe),
+ REG_FIELD_GET(UNDERRUN_PIPE_FRAME_COUNT_MASK, val),
+ REG_FIELD_GET(UNDERRUN_LINE_COUNT_MASK, val));
+}
+
+static void read_underrun_dbg_pkgc(struct intel_display *display, bool log)
+{
+ u32 val = intel_de_read(display, GEN12_DCPR_STATUS_1);
+
+ if (!(val & XE3P_UNDERRUN_PKGC))
+ return;
+
+ /*
+ * Note: If there are multiple pipes enabled, only one of them will see
+ * XE3P_UNDERRUN_PKGC set.
+ */
+ intel_de_write(display, GEN12_DCPR_STATUS_1, XE3P_UNDERRUN_PKGC);
+
+ if (log)
+ drm_err(display->drm,
+ "General FIFO underrun info: Package C-state blocking memory\n");
+}
+
+static void read_underrun_dbg_info(struct intel_display *display,
+ enum pipe pipe,
+ bool log)
+{
+ if (!HAS_UNDERRUN_DBG_INFO(display))
+ return;
+
+ read_underrun_dbg1(display, pipe, log);
+ read_underrun_dbg2(display, pipe, log);
+ intel_fbc_read_underrun_dbg_info(display, pipe, log);
+ read_underrun_dbg_pkgc(display, log);
+}
+
static bool ivb_can_enable_err_int(struct intel_display *display)
{
struct intel_crtc *crtc;
@@ -262,6 +358,17 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct intel_display *displa
old = !crtc->cpu_fifo_underrun_disabled;
crtc->cpu_fifo_underrun_disabled = !enable;
+ /*
+ * The debug bits get latched at the time of the FIFO underrun ISR bit
+ * getting set. That means that any non-zero debug bit that is read when
+ * handling a FIFO underrun interrupt has the potential to belong to
+ * another underrun event (past or future). To alleviate this problem,
+ * let's clear existing bits before enabling the interrupt, so that at
+ * least we don't get information that is too out-of-date.
+ */
+ if (enable && !old)
+ read_underrun_dbg_info(display, pipe, false);
+
if (HAS_GMCH(display))
i9xx_set_fifo_underrun_reporting(display, pipe, enable, old);
else if (display->platform.ironlake || display->platform.sandybridge)
@@ -379,6 +486,8 @@ void intel_cpu_fifo_underrun_irq_handler(struct intel_display *display,
trace_intel_cpu_fifo_underrun(display, pipe);
drm_err(display->drm, "CPU pipe %c FIFO underrun\n", pipe_name(pipe));
+
+ read_underrun_dbg_info(display, pipe, true);
}
intel_fbc_handle_fifo_underrun_irq(display);
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index 795012d7c24c..2caff677600c 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -35,8 +35,6 @@
#include <drm/drm_print.h>
#include <drm/display/drm_hdcp_helper.h>
-#include "i915_drv.h"
-#include "i915_irq.h"
#include "i915_reg.h"
#include "intel_de.h"
#include "intel_display_regs.h"
@@ -44,6 +42,7 @@
#include "intel_display_wa.h"
#include "intel_gmbus.h"
#include "intel_gmbus_regs.h"
+#include "intel_parent.h"
struct intel_gmbus {
struct i2c_adapter adapter;
@@ -391,12 +390,11 @@ intel_gpio_setup(struct intel_gmbus *bus, i915_reg_t gpio_reg)
static bool has_gmbus_irq(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
/*
* encoder->shutdown() may want to use GMBUS
* after irqs have already been disabled.
*/
- return HAS_GMBUS_IRQ(display) && intel_irqs_enabled(i915);
+ return HAS_GMBUS_IRQ(display) && intel_parent_irq_enabled(display);
}
static int gmbus_wait(struct intel_display *display, u32 status, u32 irq_en)
@@ -791,7 +789,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
struct intel_display *display = bus->display;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int ret;
wakeref = intel_display_power_get(display, POWER_DOMAIN_GMBUS);
@@ -831,7 +829,7 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
.buf = buf,
}
};
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int ret;
wakeref = intel_display_power_get(display, POWER_DOMAIN_GMBUS);
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 5e1a96223a9c..7114fc405c29 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -29,10 +29,10 @@
#include "intel_display_types.h"
#include "intel_dp_mst.h"
#include "intel_hdcp.h"
-#include "intel_hdcp_gsc.h"
#include "intel_hdcp_gsc_message.h"
#include "intel_hdcp_regs.h"
#include "intel_hdcp_shim.h"
+#include "intel_parent.h"
#include "intel_pcode.h"
#include "intel_step.h"
@@ -258,7 +258,7 @@ static bool intel_hdcp2_prerequisite(struct intel_connector *connector)
/* If MTL+ make sure gsc is loaded and proxy is setup */
if (USE_HDCP_GSC(display)) {
- if (!intel_hdcp_gsc_check_status(display->drm))
+ if (!intel_parent_hdcp_gsc_check_status(display))
return false;
}
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h
deleted file mode 100644
index 9305c14aaffe..000000000000
--- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#ifndef __INTEL_HDCP_GSC_H__
-#define __INTEL_HDCP_GSC_H__
-
-#include <linux/types.h>
-
-struct drm_device;
-struct intel_hdcp_gsc_context;
-
-ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
- void *msg_in, size_t msg_in_len,
- void *msg_out, size_t msg_out_len);
-bool intel_hdcp_gsc_check_status(struct drm_device *drm);
-
-struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm);
-void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context);
-
-#endif /* __INTEL_HDCP_GCS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c
index 98967bb148e3..781667b710b4 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c
@@ -10,8 +10,8 @@
#include "intel_display_core.h"
#include "intel_display_types.h"
-#include "intel_hdcp_gsc.h"
#include "intel_hdcp_gsc_message.h"
+#include "intel_parent.h"
static int
intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data,
@@ -44,10 +44,9 @@ intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data,
session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
session_init_in.protocol = data->protocol;
- byte = intel_hdcp_gsc_msg_send(gsc_context, &session_init_in,
- sizeof(session_init_in),
- &session_init_out,
- sizeof(session_init_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &session_init_in, sizeof(session_init_in),
+ &session_init_out, sizeof(session_init_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -106,10 +105,9 @@ intel_hdcp_gsc_verify_receiver_cert_prepare_km(struct device *dev,
memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN);
memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN);
- byte = intel_hdcp_gsc_msg_send(gsc_context, &verify_rxcert_in,
- sizeof(verify_rxcert_in),
- &verify_rxcert_out,
- sizeof(verify_rxcert_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &verify_rxcert_in, sizeof(verify_rxcert_in),
+ &verify_rxcert_out, sizeof(verify_rxcert_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte);
return byte;
@@ -169,10 +167,9 @@ intel_hdcp_gsc_verify_hprime(struct device *dev, struct hdcp_port_data *data,
memcpy(send_hprime_in.h_prime, rx_hprime->h_prime,
HDCP_2_2_H_PRIME_LEN);
- byte = intel_hdcp_gsc_msg_send(gsc_context, &send_hprime_in,
- sizeof(send_hprime_in),
- &send_hprime_out,
- sizeof(send_hprime_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &send_hprime_in, sizeof(send_hprime_in),
+ &send_hprime_out, sizeof(send_hprime_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -220,10 +217,9 @@ intel_hdcp_gsc_store_pairing_info(struct device *dev, struct hdcp_port_data *dat
memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km,
HDCP_2_2_E_KH_KM_LEN);
- byte = intel_hdcp_gsc_msg_send(gsc_context, &pairing_info_in,
- sizeof(pairing_info_in),
- &pairing_info_out,
- sizeof(pairing_info_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &pairing_info_in, sizeof(pairing_info_in),
+ &pairing_info_out, sizeof(pairing_info_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -269,8 +265,9 @@ intel_hdcp_gsc_initiate_locality_check(struct device *dev,
lc_init_in.port.physical_port = (u8)data->hdcp_ddi;
lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
- byte = intel_hdcp_gsc_msg_send(gsc_context, &lc_init_in, sizeof(lc_init_in),
- &lc_init_out, sizeof(lc_init_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &lc_init_in, sizeof(lc_init_in),
+ &lc_init_out, sizeof(lc_init_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -321,10 +318,9 @@ intel_hdcp_gsc_verify_lprime(struct device *dev, struct hdcp_port_data *data,
memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime,
HDCP_2_2_L_PRIME_LEN);
- byte = intel_hdcp_gsc_msg_send(gsc_context, &verify_lprime_in,
- sizeof(verify_lprime_in),
- &verify_lprime_out,
- sizeof(verify_lprime_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &verify_lprime_in, sizeof(verify_lprime_in),
+ &verify_lprime_out, sizeof(verify_lprime_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -370,8 +366,9 @@ intel_hdcp_gsc_get_session_key(struct device *dev,
get_skey_in.port.physical_port = (u8)data->hdcp_ddi;
get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
- byte = intel_hdcp_gsc_msg_send(gsc_context, &get_skey_in, sizeof(get_skey_in),
- &get_skey_out, sizeof(get_skey_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &get_skey_in, sizeof(get_skey_in),
+ &get_skey_out, sizeof(get_skey_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -434,10 +431,9 @@ intel_hdcp_gsc_repeater_check_flow_prepare_ack(struct device *dev,
memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids,
HDCP_2_2_RECEIVER_IDS_MAX_LEN);
- byte = intel_hdcp_gsc_msg_send(gsc_context, &verify_repeater_in,
- sizeof(verify_repeater_in),
- &verify_repeater_out,
- sizeof(verify_repeater_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &verify_repeater_in, sizeof(verify_repeater_in),
+ &verify_repeater_out, sizeof(verify_repeater_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -504,9 +500,9 @@ intel_hdcp_gsc_verify_mprime(struct device *dev,
verify_mprime_in->k = cpu_to_be16(data->k);
- byte = intel_hdcp_gsc_msg_send(gsc_context, verify_mprime_in, cmd_size,
- &verify_mprime_out,
- sizeof(verify_mprime_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ verify_mprime_in, cmd_size,
+ &verify_mprime_out, sizeof(verify_mprime_out));
kfree(verify_mprime_in);
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
@@ -552,10 +548,9 @@ static int intel_hdcp_gsc_enable_authentication(struct device *dev,
enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
enable_auth_in.stream_type = data->streams[0].stream_type;
- byte = intel_hdcp_gsc_msg_send(gsc_context, &enable_auth_in,
- sizeof(enable_auth_in),
- &enable_auth_out,
- sizeof(enable_auth_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &enable_auth_in, sizeof(enable_auth_in),
+ &enable_auth_out, sizeof(enable_auth_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -599,10 +594,9 @@ intel_hdcp_gsc_close_session(struct device *dev, struct hdcp_port_data *data)
session_close_in.port.physical_port = (u8)data->hdcp_ddi;
session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder;
- byte = intel_hdcp_gsc_msg_send(gsc_context, &session_close_in,
- sizeof(session_close_in),
- &session_close_out,
- sizeof(session_close_out));
+ byte = intel_parent_hdcp_gsc_msg_send(display, gsc_context,
+ &session_close_in, sizeof(session_close_in),
+ &session_close_out, sizeof(session_close_out));
if (byte < 0) {
drm_dbg_kms(display->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte);
return byte;
@@ -645,7 +639,7 @@ int intel_hdcp_gsc_init(struct intel_display *display)
mutex_lock(&display->hdcp.hdcp_mutex);
- gsc_context = intel_hdcp_gsc_context_alloc(display->drm);
+ gsc_context = intel_parent_hdcp_gsc_context_alloc(display);
if (IS_ERR(gsc_context)) {
ret = PTR_ERR(gsc_context);
kfree(arbiter);
@@ -665,7 +659,7 @@ out:
void intel_hdcp_gsc_fini(struct intel_display *display)
{
- intel_hdcp_gsc_context_free(display->hdcp.gsc_context);
+ intel_parent_hdcp_gsc_context_free(display, display->hdcp.gsc_context);
display->hdcp.gsc_context = NULL;
kfree(display->hdcp.arbiter);
display->hdcp.arbiter = NULL;
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 908faf17f93d..055e68810d0d 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2518,7 +2518,7 @@ intel_hdmi_set_edid(struct drm_connector *_connector)
struct intel_display *display = to_intel_display(connector);
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct i2c_adapter *ddc = connector->base.ddc;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
const struct drm_edid *drm_edid;
bool connected = false;
@@ -2561,7 +2561,7 @@ intel_hdmi_detect(struct drm_connector *_connector, bool force)
enum drm_connector_status status = connector_status_disconnected;
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s]\n",
connector->base.base.id, connector->base.name);
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 235706229ffb..970aa95ee344 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -27,8 +27,6 @@
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include "i915_drv.h"
-#include "i915_irq.h"
#include "intel_connector.h"
#include "intel_display_core.h"
#include "intel_display_power.h"
@@ -39,6 +37,7 @@
#include "intel_hdcp.h"
#include "intel_hotplug.h"
#include "intel_hotplug_irq.h"
+#include "intel_parent.h"
/**
* DOC: Hotplug
@@ -786,7 +785,7 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
container_of(work, typeof(*display), hotplug.poll_init_work);
struct drm_connector_list_iter conn_iter;
struct intel_connector *connector;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool enabled;
mutex_lock(&display->drm->mode_config.mutex);
@@ -1177,13 +1176,12 @@ bool intel_hpd_schedule_detection(struct intel_display *display)
static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
{
struct intel_display *display = m->private;
- struct drm_i915_private *dev_priv = to_i915(display->drm);
struct intel_hotplug *hotplug = &display->hotplug;
/* Synchronize with everything first in case there's been an HPD
* storm, but we haven't finished handling it in the kernel yet
*/
- intel_synchronize_irq(dev_priv);
+ intel_parent_irq_synchronize(display);
flush_work(&display->hotplug.dig_port_work);
flush_delayed_work(&display->hotplug.hotplug_work);
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
index 46c47b3d6f42..82c39e4ffa37 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
@@ -519,12 +519,9 @@ void xelpdp_pica_irq_handler(struct intel_display *display, u32 iir)
{
enum hpd_pin pin;
u32 hotplug_trigger = iir & (XELPDP_DP_ALT_HOTPLUG_MASK | XELPDP_TBT_HOTPLUG_MASK);
- u32 trigger_aux = iir & XELPDP_AUX_TC_MASK;
+ u32 trigger_aux = iir & xelpdp_pica_aux_mask(display);
u32 pin_mask = 0, long_mask = 0;
- if (DISPLAY_VER(display) >= 20)
- trigger_aux |= iir & XE2LPD_AUX_DDI_MASK;
-
for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) {
u32 val;
diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c
index 42284e9928f2..5b41abe1c64d 100644
--- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c
@@ -71,7 +71,6 @@
#include <drm/drm_print.h>
#include <drm/intel/intel_lpe_audio.h>
-#include "i915_irq.h"
#include "intel_audio_regs.h"
#include "intel_de.h"
#include "intel_lpe_audio.h"
diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c
index a67eb4f7f897..939c8975fd4c 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c
@@ -1324,11 +1324,11 @@ intel_lt_phy_config_changed(struct intel_encoder *encoder,
return true;
}
-static intel_wakeref_t intel_lt_phy_transaction_begin(struct intel_encoder *encoder)
+static struct ref_tracker *intel_lt_phy_transaction_begin(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
intel_psr_pause(intel_dp);
wakeref = intel_display_power_get(display, POWER_DOMAIN_DC_OFF);
@@ -1336,7 +1336,7 @@ static intel_wakeref_t intel_lt_phy_transaction_begin(struct intel_encoder *enco
return wakeref;
}
-static void intel_lt_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref)
+static void intel_lt_phy_transaction_end(struct intel_encoder *encoder, struct ref_tracker *wakeref)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1932,7 +1932,7 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder,
u8 owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
enum port port = encoder->port;
- intel_wakeref_t wakeref = 0;
+ struct ref_tracker *wakeref = 0;
u32 lane_phy_pulse_status = owned_lane_mask == INTEL_LT_PHY_BOTH_LANES
? (XE3PLPDP_LANE_PHY_PULSE_STATUS(0) |
XE3PLPDP_LANE_PHY_PULSE_STATUS(1))
@@ -2060,7 +2060,7 @@ void intel_lt_phy_pll_disable(struct intel_encoder *encoder)
struct intel_display *display = to_intel_display(encoder);
enum phy phy = intel_encoder_to_phy(encoder);
enum port port = encoder->port;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u8 owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder);
u32 lane_pipe_reset = owned_lane_mask == INTEL_LT_PHY_BOTH_LANES
? (XELPDP_LANE_PIPE_RESET(0) |
@@ -2137,7 +2137,7 @@ void intel_lt_phy_set_signal_levels(struct intel_encoder *encoder,
struct intel_display *display = to_intel_display(encoder);
const struct intel_ddi_buf_trans *trans;
u8 owned_lane_mask;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int n_entries, ln;
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
@@ -2222,7 +2222,7 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder,
{
u8 owned_lane_mask;
u8 lane;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
int i, j, k;
pll_state->tbt_mode = intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder));
@@ -2310,7 +2310,7 @@ void intel_xe3plpd_pll_enable(struct intel_encoder *encoder,
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (intel_tc_port_in_tbt_alt_mode(dig_port))
- intel_mtl_tbt_pll_enable(encoder, crtc_state);
+ intel_mtl_tbt_pll_enable_clock(encoder, crtc_state->port_clock);
else
intel_lt_phy_pll_enable(encoder, crtc_state);
}
@@ -2320,7 +2320,7 @@ void intel_xe3plpd_pll_disable(struct intel_encoder *encoder)
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (intel_tc_port_in_tbt_alt_mode(dig_port))
- intel_mtl_tbt_pll_disable(encoder);
+ intel_mtl_tbt_pll_disable_clock(encoder);
else
intel_lt_phy_pll_disable(encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h
index b7911acd7dcd..7659c92b6c3c 100644
--- a/drivers/gpu/drm/i915/display/intel_lt_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h
@@ -42,6 +42,4 @@ void intel_xe3plpd_pll_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_xe3plpd_pll_disable(struct intel_encoder *encoder);
-#define HAS_LT_PHY(display) (DISPLAY_VER(display) >= 35)
-
#endif /* __INTEL_LT_PHY_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 89aeb4fb340e..457d60863536 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -105,7 +105,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
wakeref = intel_display_power_get_if_enabled(display, encoder->power_domain);
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
index 0dcb0597879a..d10cbf69a5f8 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
@@ -940,7 +940,7 @@ void intel_modeset_setup_hw_state(struct intel_display *display,
{
struct intel_encoder *encoder;
struct intel_crtc *crtc;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
wakeref = intel_display_power_get(display, POWER_DOMAIN_INIT);
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
index b361a77cd235..12a00121c274 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
@@ -246,7 +246,6 @@ void intel_modeset_verify_crtc(struct intel_atomic_state *state,
verify_crtc_state(state, crtc);
intel_dpll_state_verify(state, crtc);
intel_mpllb_state_verify(state, crtc);
- intel_cx0pll_state_verify(state, crtc);
intel_lt_phy_pll_state_verify(state, crtc);
}
diff --git a/drivers/gpu/drm/i915/display/intel_panic.c b/drivers/gpu/drm/i915/display/intel_panic.c
deleted file mode 100644
index 7311ce4e8b6c..000000000000
--- a/drivers/gpu/drm/i915/display/intel_panic.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: MIT
-/* Copyright © 2025 Intel Corporation */
-
-#include <drm/drm_panic.h>
-
-#include "gem/i915_gem_object.h"
-#include "intel_display_types.h"
-#include "intel_fb.h"
-#include "intel_panic.h"
-
-struct intel_panic *intel_panic_alloc(void)
-{
- return i915_gem_object_alloc_panic();
-}
-
-int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
-{
- struct intel_framebuffer *fb = sb->private;
- struct drm_gem_object *obj = intel_fb_bo(&fb->base);
-
- return i915_gem_object_panic_setup(panic, sb, obj, fb->panic_tiling);
-}
-
-void intel_panic_finish(struct intel_panic *panic)
-{
- return i915_gem_object_panic_finish(panic);
-}
diff --git a/drivers/gpu/drm/i915/display/intel_panic.h b/drivers/gpu/drm/i915/display/intel_panic.h
deleted file mode 100644
index afb472e924aa..000000000000
--- a/drivers/gpu/drm/i915/display/intel_panic.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/* Copyright © 2025 Intel Corporation */
-
-#ifndef __INTEL_PANIC_H__
-#define __INTEL_PANIC_H__
-
-struct drm_scanout_buffer;
-struct intel_panic;
-
-struct intel_panic *intel_panic_alloc(void);
-int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb);
-void intel_panic_finish(struct intel_panic *panic);
-
-#endif /* __INTEL_PANIC_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_parent.c b/drivers/gpu/drm/i915/display/intel_parent.c
new file mode 100644
index 000000000000..72ae553f79a4
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_parent.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: MIT
+/* Copyright © 2025 Intel Corporation */
+
+/*
+ * Convenience wrapper functions to call the parent interface functions:
+ *
+ * - display->parent->SUBSTRUCT->FUNCTION()
+ * - display->parent->FUNCTION()
+ *
+ * All functions here should be named accordingly:
+ *
+ * - intel_parent_SUBSTRUCT_FUNCTION()
+ * - intel_parent_FUNCTION()
+ *
+ * These functions may use display driver specific types for parameters and
+ * return values, translating them to and from the generic types used in the
+ * function pointer interface.
+ */
+
+#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
+
+#include "intel_display_core.h"
+#include "intel_parent.h"
+
+/* hdcp */
+ssize_t intel_parent_hdcp_gsc_msg_send(struct intel_display *display,
+ struct intel_hdcp_gsc_context *gsc_context,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len)
+{
+ return display->parent->hdcp->gsc_msg_send(gsc_context, msg_in, msg_in_len, msg_out, msg_out_len);
+}
+
+bool intel_parent_hdcp_gsc_check_status(struct intel_display *display)
+{
+ return display->parent->hdcp->gsc_check_status(display->drm);
+}
+
+struct intel_hdcp_gsc_context *intel_parent_hdcp_gsc_context_alloc(struct intel_display *display)
+{
+ return display->parent->hdcp->gsc_context_alloc(display->drm);
+}
+
+void intel_parent_hdcp_gsc_context_free(struct intel_display *display,
+ struct intel_hdcp_gsc_context *gsc_context)
+{
+ display->parent->hdcp->gsc_context_free(gsc_context);
+}
+
+/* irq */
+bool intel_parent_irq_enabled(struct intel_display *display)
+{
+ return display->parent->irq->enabled(display->drm);
+}
+
+void intel_parent_irq_synchronize(struct intel_display *display)
+{
+ display->parent->irq->synchronize(display->drm);
+}
+
+/* panic */
+struct intel_panic *intel_parent_panic_alloc(struct intel_display *display)
+{
+ return display->parent->panic->alloc();
+}
+
+int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, struct drm_scanout_buffer *sb)
+{
+ return display->parent->panic->setup(panic, sb);
+}
+
+void intel_parent_panic_finish(struct intel_display *display, struct intel_panic *panic)
+{
+ display->parent->panic->finish(panic);
+}
+
+/* pc8 */
+void intel_parent_pc8_block(struct intel_display *display)
+{
+ if (drm_WARN_ON_ONCE(display->drm, !display->parent->pc8))
+ return;
+
+ display->parent->pc8->block(display->drm);
+}
+
+void intel_parent_pc8_unblock(struct intel_display *display)
+{
+ if (drm_WARN_ON_ONCE(display->drm, !display->parent->pc8))
+ return;
+
+ display->parent->pc8->unblock(display->drm);
+}
+
+/* rps */
+bool intel_parent_rps_available(struct intel_display *display)
+{
+ return display->parent->rps;
+}
+
+void intel_parent_rps_boost_if_not_started(struct intel_display *display, struct dma_fence *fence)
+{
+ if (display->parent->rps)
+ display->parent->rps->boost_if_not_started(fence);
+}
+
+void intel_parent_rps_mark_interactive(struct intel_display *display, bool interactive)
+{
+ if (display->parent->rps)
+ display->parent->rps->mark_interactive(display->drm, interactive);
+}
+
+void intel_parent_rps_ilk_irq_handler(struct intel_display *display)
+{
+ if (display->parent->rps)
+ display->parent->rps->ilk_irq_handler(display->drm);
+}
+
+/* stolen */
+int intel_parent_stolen_insert_node_in_range(struct intel_display *display,
+ struct intel_stolen_node *node, u64 size,
+ unsigned int align, u64 start, u64 end)
+{
+ return display->parent->stolen->insert_node_in_range(node, size, align, start, end);
+}
+
+int intel_parent_stolen_insert_node(struct intel_display *display, struct intel_stolen_node *node, u64 size,
+ unsigned int align)
+{
+ if (drm_WARN_ON_ONCE(display->drm, !display->parent->stolen->insert_node))
+ return -ENODEV;
+
+ return display->parent->stolen->insert_node(node, size, align);
+}
+
+void intel_parent_stolen_remove_node(struct intel_display *display,
+ struct intel_stolen_node *node)
+{
+ display->parent->stolen->remove_node(node);
+}
+
+bool intel_parent_stolen_initialized(struct intel_display *display)
+{
+ return display->parent->stolen->initialized(display->drm);
+}
+
+bool intel_parent_stolen_node_allocated(struct intel_display *display,
+ const struct intel_stolen_node *node)
+{
+ return display->parent->stolen->node_allocated(node);
+}
+
+u32 intel_parent_stolen_node_offset(struct intel_display *display, struct intel_stolen_node *node)
+{
+ return display->parent->stolen->node_offset(node);
+}
+
+u64 intel_parent_stolen_area_address(struct intel_display *display)
+{
+ if (drm_WARN_ON_ONCE(display->drm, !display->parent->stolen->area_address))
+ return 0;
+
+ return display->parent->stolen->area_address(display->drm);
+}
+
+u64 intel_parent_stolen_area_size(struct intel_display *display)
+{
+ if (drm_WARN_ON_ONCE(display->drm, !display->parent->stolen->area_size))
+ return 0;
+
+ return display->parent->stolen->area_size(display->drm);
+}
+
+u64 intel_parent_stolen_node_address(struct intel_display *display, struct intel_stolen_node *node)
+{
+ return display->parent->stolen->node_address(node);
+}
+
+u64 intel_parent_stolen_node_size(struct intel_display *display, const struct intel_stolen_node *node)
+{
+ return display->parent->stolen->node_size(node);
+}
+
+struct intel_stolen_node *intel_parent_stolen_node_alloc(struct intel_display *display)
+{
+ return display->parent->stolen->node_alloc(display->drm);
+}
+
+void intel_parent_stolen_node_free(struct intel_display *display, const struct intel_stolen_node *node)
+{
+ display->parent->stolen->node_free(node);
+}
+
+/* generic */
+void intel_parent_fence_priority_display(struct intel_display *display, struct dma_fence *fence)
+{
+ if (display->parent->fence_priority_display)
+ display->parent->fence_priority_display(fence);
+}
+
+bool intel_parent_has_auxccs(struct intel_display *display)
+{
+ return display->parent->has_auxccs && display->parent->has_auxccs(display->drm);
+}
+
+bool intel_parent_has_fenced_regions(struct intel_display *display)
+{
+ return display->parent->has_fenced_regions && display->parent->has_fenced_regions(display->drm);
+}
+
+bool intel_parent_vgpu_active(struct intel_display *display)
+{
+ return display->parent->vgpu_active && display->parent->vgpu_active(display->drm);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_parent.h b/drivers/gpu/drm/i915/display/intel_parent.h
new file mode 100644
index 000000000000..47cdc14f9aa2
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_parent.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __INTEL_PARENT_H__
+#define __INTEL_PARENT_H__
+
+#include <linux/types.h>
+
+struct dma_fence;
+struct drm_scanout_buffer;
+struct intel_display;
+struct intel_hdcp_gsc_context;
+struct intel_panic;
+struct intel_stolen_node;
+
+/* hdcp */
+ssize_t intel_parent_hdcp_gsc_msg_send(struct intel_display *display,
+ struct intel_hdcp_gsc_context *gsc_context,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len);
+bool intel_parent_hdcp_gsc_check_status(struct intel_display *display);
+struct intel_hdcp_gsc_context *intel_parent_hdcp_gsc_context_alloc(struct intel_display *display);
+void intel_parent_hdcp_gsc_context_free(struct intel_display *display,
+ struct intel_hdcp_gsc_context *gsc_context);
+
+/* irq */
+bool intel_parent_irq_enabled(struct intel_display *display);
+void intel_parent_irq_synchronize(struct intel_display *display);
+
+/* panic */
+struct intel_panic *intel_parent_panic_alloc(struct intel_display *display);
+int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, struct drm_scanout_buffer *sb);
+void intel_parent_panic_finish(struct intel_display *display, struct intel_panic *panic);
+
+/* pc8 */
+void intel_parent_pc8_block(struct intel_display *display);
+void intel_parent_pc8_unblock(struct intel_display *display);
+
+/* rps */
+bool intel_parent_rps_available(struct intel_display *display);
+void intel_parent_rps_boost_if_not_started(struct intel_display *display, struct dma_fence *fence);
+void intel_parent_rps_mark_interactive(struct intel_display *display, bool interactive);
+void intel_parent_rps_ilk_irq_handler(struct intel_display *display);
+
+/* stolen */
+int intel_parent_stolen_insert_node_in_range(struct intel_display *display,
+ struct intel_stolen_node *node, u64 size,
+ unsigned int align, u64 start, u64 end);
+int intel_parent_stolen_insert_node(struct intel_display *display, struct intel_stolen_node *node, u64 size,
+ unsigned int align);
+void intel_parent_stolen_remove_node(struct intel_display *display,
+ struct intel_stolen_node *node);
+bool intel_parent_stolen_initialized(struct intel_display *display);
+bool intel_parent_stolen_node_allocated(struct intel_display *display,
+ const struct intel_stolen_node *node);
+u32 intel_parent_stolen_node_offset(struct intel_display *display, struct intel_stolen_node *node);
+u64 intel_parent_stolen_area_address(struct intel_display *display);
+u64 intel_parent_stolen_area_size(struct intel_display *display);
+u64 intel_parent_stolen_node_address(struct intel_display *display, struct intel_stolen_node *node);
+u64 intel_parent_stolen_node_size(struct intel_display *display, const struct intel_stolen_node *node);
+struct intel_stolen_node *intel_parent_stolen_node_alloc(struct intel_display *display);
+void intel_parent_stolen_node_free(struct intel_display *display, const struct intel_stolen_node *node);
+
+/* generic */
+bool intel_parent_has_auxccs(struct intel_display *display);
+bool intel_parent_has_fenced_regions(struct intel_display *display);
+bool intel_parent_vgpu_active(struct intel_display *display);
+void intel_parent_fence_priority_display(struct intel_display *display, struct dma_fence *fence);
+
+#endif /* __INTEL_PARENT_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
index 1f27643412f1..57586c78582d 100644
--- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
@@ -30,13 +30,12 @@
#include <drm/drm_print.h>
-#include "i915_drv.h"
-#include "i915_irq.h"
#include "intel_atomic.h"
#include "intel_de.h"
#include "intel_display_irq.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
+#include "intel_parent.h"
#include "intel_pipe_crc.h"
#include "intel_pipe_crc_regs.h"
@@ -589,7 +588,7 @@ int intel_crtc_set_crc_source(struct drm_crtc *_crtc, const char *source_name)
enum intel_display_power_domain power_domain;
enum intel_pipe_crc_source source;
enum pipe pipe = crtc->pipe;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 val = 0; /* shut up gcc */
int ret = 0;
bool enable;
@@ -658,7 +657,6 @@ void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc)
void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(crtc);
- struct drm_i915_private *dev_priv = to_i915(display->drm);
struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc;
enum pipe pipe = crtc->pipe;
@@ -669,5 +667,5 @@ void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc)
intel_de_write(display, PIPE_CRC_CTL(display, pipe), 0);
intel_de_posting_read(display, PIPE_CRC_CTL(display, pipe));
- intel_synchronize_irq(dev_priv);
+ intel_parent_irq_synchronize(display);
}
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index ab6a58530b39..3dc2ed52147f 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -45,7 +45,6 @@
#include <drm/drm_panic.h>
#include <drm/drm_print.h>
-#include "gem/i915_gem_object.h"
#include "i9xx_plane_regs.h"
#include "intel_cdclk.h"
#include "intel_cursor.h"
@@ -56,7 +55,7 @@
#include "intel_fb.h"
#include "intel_fb_pin.h"
#include "intel_fbdev.h"
-#include "intel_panic.h"
+#include "intel_parent.h"
#include "intel_plane.h"
#include "intel_psr.h"
#include "skl_scaler.h"
@@ -179,25 +178,29 @@ bool intel_plane_needs_physical(struct intel_plane *plane)
DISPLAY_INFO(display)->cursor_needs_physical;
}
-bool intel_plane_can_async_flip(struct intel_plane *plane, u32 format,
+bool intel_plane_can_async_flip(struct intel_plane *plane,
+ const struct drm_format_info *info,
u64 modifier)
{
- if (intel_format_info_is_yuv_semiplanar(drm_format_info(format), modifier) ||
- format == DRM_FORMAT_C8)
+ if (intel_format_info_is_yuv_semiplanar(info, modifier) ||
+ info->format == DRM_FORMAT_C8)
return false;
return plane->can_async_flip && plane->can_async_flip(modifier);
}
-bool intel_plane_format_mod_supported_async(struct drm_plane *plane,
- u32 format,
- u64 modifier)
+bool intel_plane_format_mod_supported_async(struct drm_plane *_plane,
+ u32 format, u64 modifier)
{
- if (!plane->funcs->format_mod_supported(plane, format, modifier))
+ struct intel_plane *plane = to_intel_plane(_plane);
+ const struct drm_format_info *info;
+
+ if (!plane->base.funcs->format_mod_supported(&plane->base, format, modifier))
return false;
- return intel_plane_can_async_flip(to_intel_plane(plane),
- format, modifier);
+ info = drm_get_format_info(plane->base.dev, format, modifier);
+
+ return intel_plane_can_async_flip(plane, info, modifier);
}
unsigned int intel_adjusted_rate(const struct drm_rect *src,
@@ -651,11 +654,10 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr
ilk_must_disable_cxsr(new_crtc_state, old_plane_state, new_plane_state))
new_crtc_state->disable_cxsr = true;
- if (intel_plane_do_async_flip(plane, old_crtc_state, new_crtc_state)) {
+ if (intel_plane_do_async_flip(plane, old_crtc_state, new_crtc_state))
new_crtc_state->do_async_flip = true;
- new_crtc_state->async_flip_planes |= BIT(plane->id);
- } else if (plane->need_async_flip_toggle_wa &&
- new_crtc_state->uapi.async_flip) {
+
+ if (new_crtc_state->uapi.async_flip) {
/*
* On platforms with double buffered async flip bit we
* set the bit already one frame early during the sync
@@ -663,6 +665,9 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr
* hardware will therefore be ready to perform a real
* async flip during the next commit, without having
* to wait yet another frame for the bit to latch.
+ *
+ * async_flip_planes bitmask is also used by selective
+ * fetch calculation to choose full frame update.
*/
new_crtc_state->async_flip_planes |= BIT(plane->id);
}
@@ -1235,8 +1240,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
goto unpin_fb;
if (new_plane_state->uapi.fence) {
- i915_gem_fence_wait_priority_display(new_plane_state->uapi.fence);
-
+ intel_parent_fence_priority_display(display, new_plane_state->uapi.fence);
intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc,
new_plane_state->uapi.fence);
}
@@ -1330,33 +1334,33 @@ static unsigned int intel_4tile_get_offset(unsigned int width, unsigned int x, u
return offset;
}
-static void intel_panic_flush(struct drm_plane *plane)
+static void intel_panic_flush(struct drm_plane *_plane)
{
- struct intel_plane_state *plane_state = to_intel_plane_state(plane->state);
- struct intel_crtc_state *crtc_state = to_intel_crtc_state(plane->state->crtc->state);
- struct intel_plane *iplane = to_intel_plane(plane);
- struct intel_display *display = to_intel_display(iplane);
- struct drm_framebuffer *fb = plane_state->hw.fb;
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct intel_plane *plane = to_intel_plane(_plane);
+ struct intel_display *display = to_intel_display(plane);
+ const struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state);
+ struct intel_crtc *crtc = to_intel_crtc(plane_state->hw.crtc);
+ const struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
+ const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb);
- intel_panic_finish(intel_fb->panic);
+ intel_parent_panic_finish(display, fb->panic);
if (crtc_state->enable_psr2_sel_fetch) {
/* Force a full update for psr2 */
- intel_psr2_panic_force_full_update(display, crtc_state);
+ intel_psr2_panic_force_full_update(crtc_state);
}
/* Flush the cache and don't disable tiling if it's the fbdev framebuffer.*/
- if (intel_fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) {
+ if (fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) {
struct iosys_map map;
intel_fbdev_get_map(display->fbdev.fbdev, &map);
- drm_clflush_virt_range(map.vaddr, fb->pitches[0] * fb->height);
+ drm_clflush_virt_range(map.vaddr, fb->base.pitches[0] * fb->base.height);
return;
}
- if (fb->modifier && iplane->disable_tiling)
- iplane->disable_tiling(iplane);
+ if (fb->base.modifier != DRM_FORMAT_MOD_LINEAR && plane->disable_tiling)
+ plane->disable_tiling(plane);
}
static unsigned int (*intel_get_tiling_func(u64 fb_modifier))(unsigned int width,
@@ -1394,45 +1398,43 @@ static int intel_get_scanout_buffer(struct drm_plane *plane,
{
struct intel_plane_state *plane_state;
struct drm_gem_object *obj;
- struct drm_framebuffer *fb;
- struct intel_framebuffer *intel_fb;
+ struct intel_framebuffer *fb;
struct intel_display *display = to_intel_display(plane->dev);
if (!plane->state || !plane->state->fb || !plane->state->visible)
return -ENODEV;
plane_state = to_intel_plane_state(plane->state);
- fb = plane_state->hw.fb;
- intel_fb = to_intel_framebuffer(fb);
+ fb = to_intel_framebuffer(plane_state->hw.fb);
- obj = intel_fb_bo(fb);
+ obj = intel_fb_bo(&fb->base);
if (!obj)
return -ENODEV;
- if (intel_fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) {
+ if (fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) {
intel_fbdev_get_map(display->fbdev.fbdev, &sb->map[0]);
} else {
int ret;
/* Can't disable tiling if DPT is in use */
- if (intel_fb_uses_dpt(fb)) {
- if (fb->format->cpp[0] != 4)
+ if (intel_fb_uses_dpt(&fb->base)) {
+ if (fb->base.format->cpp[0] != 4)
return -EOPNOTSUPP;
- intel_fb->panic_tiling = intel_get_tiling_func(fb->modifier);
- if (!intel_fb->panic_tiling)
+ fb->panic_tiling = intel_get_tiling_func(fb->base.modifier);
+ if (!fb->panic_tiling)
return -EOPNOTSUPP;
}
- sb->private = intel_fb;
- ret = intel_panic_setup(intel_fb->panic, sb);
+ sb->private = fb;
+ ret = intel_parent_panic_setup(display, fb->panic, sb);
if (ret)
return ret;
}
- sb->width = fb->width;
- sb->height = fb->height;
+ sb->width = fb->base.width;
+ sb->height = fb->base.height;
/* Use the generic linear format, because tiling, RC, CCS, CC
* will be disabled in disable_tiling()
*/
- sb->format = drm_format_info(fb->format->format);
- sb->pitch[0] = fb->pitches[0];
+ sb->format = drm_format_info(fb->base.format->format);
+ sb->pitch[0] = fb->base.pitches[0];
return 0;
}
@@ -1464,7 +1466,7 @@ void intel_plane_init_cursor_vblank_work(struct intel_plane_state *old_plane_sta
old_plane_state->ggtt_vma == new_plane_state->ggtt_vma)
return;
- drm_vblank_work_init(&old_plane_state->unpin_work, old_plane_state->uapi.crtc,
+ drm_vblank_work_init(&old_plane_state->unpin_work, old_plane_state->hw.crtc,
intel_cursor_unpin_work);
}
diff --git a/drivers/gpu/drm/i915/display/intel_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h
index 4e99df9de3e8..5a8f2f3baab5 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_plane.h
@@ -8,6 +8,7 @@
#include <linux/types.h>
+struct drm_format_info;
struct drm_plane;
struct drm_property;
struct drm_rect;
@@ -21,7 +22,8 @@ enum plane_id;
struct intel_plane *
intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id);
-bool intel_plane_can_async_flip(struct intel_plane *plane, u32 format,
+bool intel_plane_can_async_flip(struct intel_plane *plane,
+ const struct drm_format_info *info,
u64 modifier);
unsigned int intel_adjusted_rate(const struct drm_rect *src,
const struct drm_rect *dst,
diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c
index a1de1ec564d1..ff1afd3a8f20 100644
--- a/drivers/gpu/drm/i915/display/intel_plane_initial.c
+++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c
@@ -39,7 +39,7 @@ intel_reuse_initial_plane_obj(struct intel_crtc *this,
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
- if (!crtc_state->uapi.active)
+ if (!crtc_state->hw.active)
continue;
if (!plane_state->ggtt_vma)
@@ -411,10 +411,12 @@ void intel_initial_plane_config(struct intel_display *display)
struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
struct intel_initial_plane_config *plane_config =
&plane_configs[crtc->pipe];
- if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
+ if (!crtc_state->hw.active)
continue;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c
index 25692a547764..b217ec7aa758 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.c
+++ b/drivers/gpu/drm/i915/display/intel_pps.c
@@ -67,10 +67,10 @@ static const char *pps_name(struct intel_dp *intel_dp)
return "PPS <invalid>";
}
-intel_wakeref_t intel_pps_lock(struct intel_dp *intel_dp)
+struct ref_tracker *intel_pps_lock(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
/*
* See vlv_pps_reset_all() why we need a power domain reference here.
@@ -81,8 +81,7 @@ intel_wakeref_t intel_pps_lock(struct intel_dp *intel_dp)
return wakeref;
}
-intel_wakeref_t intel_pps_unlock(struct intel_dp *intel_dp,
- intel_wakeref_t wakeref)
+struct ref_tracker *intel_pps_unlock(struct intel_dp *intel_dp, struct ref_tracker *wakeref)
{
struct intel_display *display = to_intel_display(intel_dp);
@@ -697,12 +696,10 @@ static void wait_panel_power_cycle(struct intel_dp *intel_dp)
void intel_pps_wait_power_cycle(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
wait_panel_power_cycle(intel_dp);
}
@@ -811,14 +808,13 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
void intel_pps_vdd_on(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_wakeref_t wakeref;
bool vdd;
if (!intel_dp_is_edp(intel_dp))
return;
vdd = false;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
vdd = intel_pps_vdd_on_unlocked(intel_dp);
INTEL_DISPLAY_STATE_WARN(display, !vdd, "[ENCODER:%d:%s] %s VDD already requested on\n",
dp_to_dig_port(intel_dp)->base.base.base.id,
@@ -873,8 +869,6 @@ static void intel_pps_vdd_off_sync_unlocked(struct intel_dp *intel_dp)
void intel_pps_vdd_off_sync(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
if (!intel_dp_is_edp(intel_dp))
return;
@@ -883,7 +877,7 @@ void intel_pps_vdd_off_sync(struct intel_dp *intel_dp)
* vdd might still be enabled due to the delayed vdd off.
* Make sure vdd is actually turned off here.
*/
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_pps_vdd_off_sync_unlocked(intel_dp);
}
@@ -892,9 +886,8 @@ static void edp_panel_vdd_work(struct work_struct *__work)
struct intel_pps *pps = container_of(to_delayed_work(__work),
struct intel_pps, panel_vdd_work);
struct intel_dp *intel_dp = container_of(pps, struct intel_dp, pps);
- intel_wakeref_t wakeref;
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
if (!intel_dp->pps.want_panel_vdd)
intel_pps_vdd_off_sync_unlocked(intel_dp);
}
@@ -952,12 +945,10 @@ void intel_pps_vdd_off_unlocked(struct intel_dp *intel_dp, bool sync)
void intel_pps_vdd_off(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_pps_vdd_off_unlocked(intel_dp, false);
}
@@ -1026,12 +1017,10 @@ void intel_pps_on_unlocked(struct intel_dp *intel_dp)
void intel_pps_on(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_pps_on_unlocked(intel_dp);
}
@@ -1082,12 +1071,10 @@ void intel_pps_off_unlocked(struct intel_dp *intel_dp)
void intel_pps_off(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_pps_off_unlocked(intel_dp);
}
@@ -1095,7 +1082,6 @@ void intel_pps_off(struct intel_dp *intel_dp)
void intel_pps_backlight_on(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_wakeref_t wakeref;
/*
* If we enable the backlight right away following a panel power
@@ -1105,7 +1091,7 @@ void intel_pps_backlight_on(struct intel_dp *intel_dp)
*/
wait_backlight_on(intel_dp);
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
u32 pp;
@@ -1121,12 +1107,11 @@ void intel_pps_backlight_on(struct intel_dp *intel_dp)
void intel_pps_backlight_off(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_wakeref_t wakeref;
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
i915_reg_t pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
u32 pp;
@@ -1149,11 +1134,10 @@ void intel_pps_backlight_power(struct intel_connector *connector, bool enable)
{
struct intel_display *display = to_intel_display(connector);
struct intel_dp *intel_dp = intel_attached_dp(connector);
- intel_wakeref_t wakeref;
bool is_enabled;
is_enabled = false;
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
is_enabled = ilk_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
if (is_enabled == enable)
return;
@@ -1251,9 +1235,7 @@ void vlv_pps_pipe_init(struct intel_dp *intel_dp)
/* Call on all DP, not just eDP */
void vlv_pps_pipe_reset(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_dp->pps.vlv_active_pipe = vlv_active_pipe(intel_dp);
}
@@ -1329,9 +1311,7 @@ void vlv_pps_port_disable(struct intel_encoder *encoder,
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- intel_wakeref_t wakeref;
-
- with_intel_pps_lock(intel_dp, wakeref)
+ with_intel_pps_lock(intel_dp)
intel_dp->pps.vlv_active_pipe = INVALID_PIPE;
}
@@ -1362,10 +1342,9 @@ static void pps_vdd_init(struct intel_dp *intel_dp)
bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
bool have_power = false;
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
have_power = edp_have_panel_power(intel_dp) ||
edp_have_panel_vdd(intel_dp);
}
@@ -1692,12 +1671,11 @@ static void pps_init_registers(struct intel_dp *intel_dp, bool force_disable_vdd
void intel_pps_encoder_reset(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_wakeref_t wakeref;
if (!intel_dp_is_edp(intel_dp))
return;
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
/*
* Reinit the power sequencer also on the resume path, in case
* BIOS did something nasty with it.
@@ -1716,7 +1694,6 @@ void intel_pps_encoder_reset(struct intel_dp *intel_dp)
bool intel_pps_init(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
bool ret;
intel_dp->pps.initializing = true;
@@ -1724,7 +1701,7 @@ bool intel_pps_init(struct intel_dp *intel_dp)
pps_init_timestamps(intel_dp);
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
ret = pps_initial_setup(intel_dp);
pps_init_delays(intel_dp);
@@ -1760,9 +1737,7 @@ static void pps_init_late(struct intel_dp *intel_dp)
void intel_pps_init_late(struct intel_dp *intel_dp)
{
- intel_wakeref_t wakeref;
-
- with_intel_pps_lock(intel_dp, wakeref) {
+ with_intel_pps_lock(intel_dp) {
/* Reinit delays after per-panel info has been parsed from VBT */
pps_init_late(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_pps.h b/drivers/gpu/drm/i915/display/intel_pps.h
index c83007152f07..f7c96d75be45 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.h
+++ b/drivers/gpu/drm/i915/display/intel_pps.h
@@ -8,20 +8,22 @@
#include <linux/types.h>
-#include "intel_wakeref.h"
-
enum pipe;
struct intel_connector;
struct intel_crtc_state;
struct intel_display;
struct intel_dp;
struct intel_encoder;
+struct ref_tracker;
+
+struct ref_tracker *intel_pps_lock(struct intel_dp *intel_dp);
+struct ref_tracker *intel_pps_unlock(struct intel_dp *intel_dp, struct ref_tracker *wakeref);
-intel_wakeref_t intel_pps_lock(struct intel_dp *intel_dp);
-intel_wakeref_t intel_pps_unlock(struct intel_dp *intel_dp, intel_wakeref_t wakeref);
+#define __with_intel_pps_lock(dp, wf) \
+ for (struct ref_tracker *(wf) = intel_pps_lock(dp); (wf); (wf) = intel_pps_unlock((dp), (wf)))
-#define with_intel_pps_lock(dp, wf) \
- for ((wf) = intel_pps_lock(dp); (wf); (wf) = intel_pps_unlock((dp), (wf)))
+#define with_intel_pps_lock(dp) \
+ __with_intel_pps_lock((dp), __UNIQUE_ID(wakeref))
void intel_pps_backlight_on(struct intel_dp *intel_dp);
void intel_pps_backlight_off(struct intel_dp *intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 08bca4573974..91f4ac86c7ad 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -494,82 +494,37 @@ static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp)
return val;
}
-static u8 intel_dp_get_su_capability(struct intel_dp *intel_dp)
-{
- u8 su_capability = 0;
-
- if (intel_dp->psr.sink_panel_replay_su_support) {
- if (drm_dp_dpcd_read_byte(&intel_dp->aux,
- DP_PANEL_REPLAY_CAP_CAPABILITY,
- &su_capability) < 0)
- return 0;
- } else {
- su_capability = intel_dp->psr_dpcd[1];
- }
-
- return su_capability;
-}
-
-static unsigned int
-intel_dp_get_su_x_granularity_offset(struct intel_dp *intel_dp)
-{
- return intel_dp->psr.sink_panel_replay_su_support ?
- DP_PANEL_REPLAY_CAP_X_GRANULARITY :
- DP_PSR2_SU_X_GRANULARITY;
-}
-
-static unsigned int
-intel_dp_get_su_y_granularity_offset(struct intel_dp *intel_dp)
-{
- return intel_dp->psr.sink_panel_replay_su_support ?
- DP_PANEL_REPLAY_CAP_Y_GRANULARITY :
- DP_PSR2_SU_Y_GRANULARITY;
-}
-
-/*
- * Note: Bits related to granularity are same in panel replay and psr
- * registers. Rely on PSR definitions on these "common" bits.
- */
-static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
+static void _psr_compute_su_granularity(struct intel_dp *intel_dp,
+ struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
ssize_t r;
- u16 w;
+ __le16 w;
u8 y;
/*
- * TODO: Do we need to take into account panel supporting both PSR and
- * Panel replay?
- */
-
- /*
* If sink don't have specific granularity requirements set legacy
* ones.
*/
- if (!(intel_dp_get_su_capability(intel_dp) &
- DP_PSR2_SU_GRANULARITY_REQUIRED)) {
+ if (!(connector->dp.psr_caps.dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED)) {
/* As PSR2 HW sends full lines, we do not care about x granularity */
- w = 4;
+ w = cpu_to_le16(4);
y = 4;
goto exit;
}
- r = drm_dp_dpcd_read(&intel_dp->aux,
- intel_dp_get_su_x_granularity_offset(intel_dp),
- &w, 2);
- if (r != 2)
+ r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, sizeof(w));
+ if (r != sizeof(w))
drm_dbg_kms(display->drm,
"Unable to read selective update x granularity\n");
/*
* Spec says that if the value read is 0 the default granularity should
* be used instead.
*/
- if (r != 2 || w == 0)
- w = 4;
+ if (r != sizeof(w) || w == 0)
+ w = cpu_to_le16(4);
- r = drm_dp_dpcd_read(&intel_dp->aux,
- intel_dp_get_su_y_granularity_offset(intel_dp),
- &y, 1);
+ r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1);
if (r != 1) {
drm_dbg_kms(display->drm,
"Unable to read selective update y granularity\n");
@@ -579,17 +534,17 @@ static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
y = 1;
exit:
- intel_dp->psr.su_w_granularity = w;
- intel_dp->psr.su_y_granularity = y;
+ connector->dp.psr_caps.su_w_granularity = le16_to_cpu(w);
+ connector->dp.psr_caps.su_y_granularity = y;
}
static enum intel_panel_replay_dsc_support
-compute_pr_dsc_support(struct intel_dp *intel_dp)
+compute_pr_dsc_support(struct intel_connector *connector)
{
u8 pr_dsc_mode;
u8 val;
- val = intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)];
+ val = connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)];
pr_dsc_mode = REG_FIELD_GET8(DP_PANEL_REPLAY_DSC_DECODE_CAPABILITY_IN_PR_MASK, val);
switch (pr_dsc_mode) {
@@ -621,7 +576,31 @@ static const char *panel_replay_dsc_support_str(enum intel_panel_replay_dsc_supp
};
}
-static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
+static void _panel_replay_compute_su_granularity(struct intel_connector *connector)
+{
+ u16 w;
+ u8 y;
+
+ if (!(connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
+ DP_PANEL_REPLAY_SU_GRANULARITY_REQUIRED)) {
+ w = 4;
+ y = 4;
+ goto exit;
+ }
+
+ /*
+ * Spec says that if the value read is 0 the default granularity should
+ * be used instead.
+ */
+ w = le16_to_cpu(*(__le16 *)&connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_X_GRANULARITY)]) ? : 4;
+ y = connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_Y_GRANULARITY)] ? : 1;
+
+exit:
+ connector->dp.panel_replay_caps.su_w_granularity = w;
+ connector->dp.panel_replay_caps.su_y_granularity = y;
+}
+
+static void _panel_replay_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
@@ -631,11 +610,12 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
return;
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PANEL_REPLAY_CAP_SUPPORT,
- &intel_dp->pr_dpcd, sizeof(intel_dp->pr_dpcd));
+ &connector->dp.panel_replay_caps.dpcd,
+ sizeof(connector->dp.panel_replay_caps.dpcd));
if (ret < 0)
return;
- if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
+ if (!(connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
DP_PANEL_REPLAY_SUPPORT))
return;
@@ -646,7 +626,7 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
return;
}
- if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
+ if (!(connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT)) {
drm_dbg_kms(display->drm,
"Panel doesn't support early transport, eDP Panel Replay not possible\n");
@@ -654,36 +634,40 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
}
}
+ connector->dp.panel_replay_caps.support = true;
intel_dp->psr.sink_panel_replay_support = true;
- if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
- DP_PANEL_REPLAY_SU_SUPPORT)
- intel_dp->psr.sink_panel_replay_su_support = true;
+ if (connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
+ DP_PANEL_REPLAY_SU_SUPPORT) {
+ connector->dp.panel_replay_caps.su_support = true;
+
+ _panel_replay_compute_su_granularity(connector);
+ }
- intel_dp->psr.sink_panel_replay_dsc_support = compute_pr_dsc_support(intel_dp);
+ connector->dp.panel_replay_caps.dsc_support = compute_pr_dsc_support(connector);
drm_dbg_kms(display->drm,
"Panel replay %sis supported by panel (in DSC mode: %s)\n",
- intel_dp->psr.sink_panel_replay_su_support ?
+ connector->dp.panel_replay_caps.su_support ?
"selective_update " : "",
- panel_replay_dsc_support_str(intel_dp->psr.sink_panel_replay_dsc_support));
+ panel_replay_dsc_support_str(connector->dp.panel_replay_caps.dsc_support));
}
-static void _psr_init_dpcd(struct intel_dp *intel_dp)
+static void _psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
- ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd,
- sizeof(intel_dp->psr_dpcd));
+ ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PSR_SUPPORT, connector->dp.psr_caps.dpcd,
+ sizeof(connector->dp.psr_caps.dpcd));
if (ret < 0)
return;
- if (!intel_dp->psr_dpcd[0])
+ if (!connector->dp.psr_caps.dpcd[0])
return;
drm_dbg_kms(display->drm, "eDP panel supports PSR version %x\n",
- intel_dp->psr_dpcd[0]);
+ connector->dp.psr_caps.dpcd[0]);
if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) {
drm_dbg_kms(display->drm,
@@ -697,13 +681,14 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp)
return;
}
+ connector->dp.psr_caps.support = true;
intel_dp->psr.sink_support = true;
- intel_dp->psr.sink_sync_latency =
- intel_dp_get_sink_sync_latency(intel_dp);
+
+ connector->dp.psr_caps.sync_latency = intel_dp_get_sink_sync_latency(intel_dp);
if (DISPLAY_VER(display) >= 9 &&
- intel_dp->psr_dpcd[0] >= DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) {
- bool y_req = intel_dp->psr_dpcd[1] &
+ connector->dp.psr_caps.dpcd[0] >= DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) {
+ bool y_req = connector->dp.psr_caps.dpcd[1] &
DP_PSR2_SU_Y_COORDINATE_REQUIRED;
/*
@@ -717,22 +702,21 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp)
* Y-coordinate requirement panels we would need to enable
* GTC first.
*/
- intel_dp->psr.sink_psr2_support = y_req &&
+ connector->dp.psr_caps.su_support = y_req &&
intel_alpm_aux_wake_supported(intel_dp);
drm_dbg_kms(display->drm, "PSR2 %ssupported\n",
- intel_dp->psr.sink_psr2_support ? "" : "not ");
+ connector->dp.psr_caps.su_support ? "" : "not ");
}
+
+ if (connector->dp.psr_caps.su_support)
+ _psr_compute_su_granularity(intel_dp, connector);
}
-void intel_psr_init_dpcd(struct intel_dp *intel_dp)
+void intel_psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
- _psr_init_dpcd(intel_dp);
+ _psr_init_dpcd(intel_dp, connector);
- _panel_replay_init_dpcd(intel_dp);
-
- if (intel_dp->psr.sink_psr2_support ||
- intel_dp->psr.sink_panel_replay_su_support)
- intel_dp_get_su_granularity(intel_dp);
+ _panel_replay_init_dpcd(intel_dp, connector);
}
static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
@@ -772,8 +756,9 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp)
aux_ctl);
}
-static bool psr2_su_region_et_valid(struct intel_dp *intel_dp, bool panel_replay)
+static bool psr2_su_region_et_valid(struct intel_connector *connector, bool panel_replay)
{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_display *display = to_intel_display(intel_dp);
if (DISPLAY_VER(display) < 20 || !intel_dp_is_edp(intel_dp) ||
@@ -781,9 +766,9 @@ static bool psr2_su_region_et_valid(struct intel_dp *intel_dp, bool panel_replay
return false;
return panel_replay ?
- intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
+ connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT :
- intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED;
+ connector->dp.psr_caps.dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED;
}
static void _panel_replay_enable_sink(struct intel_dp *intel_dp,
@@ -924,7 +909,7 @@ static u8 psr_compute_idle_frames(struct intel_dp *intel_dp)
* off-by-one issue that HW has in some cases.
*/
idle_frames = max(6, connector->panel.vbt.psr.idle_frames);
- idle_frames = max(idle_frames, intel_dp->psr.sink_sync_latency + 1);
+ idle_frames = max(idle_frames, connector->dp.psr_caps.sync_latency + 1);
if (drm_WARN_ON(display->drm, idle_frames > 0xf))
idle_frames = 0xf;
@@ -1019,10 +1004,11 @@ static int psr2_block_count(struct intel_dp *intel_dp)
static u8 frames_before_su_entry(struct intel_dp *intel_dp)
{
+ struct intel_connector *connector = intel_dp->attached_connector;
u8 frames_before_su_entry;
frames_before_su_entry = max_t(u8,
- intel_dp->psr.sink_sync_latency + 1,
+ connector->dp.psr_caps.sync_latency + 1,
2);
/* Entry setup frames must be at least 1 less than frames before SU entry */
@@ -1304,25 +1290,32 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
return crtc_state->enable_psr2_sel_fetch = true;
}
-static bool psr2_granularity_check(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state)
+static bool psr2_granularity_check(struct intel_crtc_state *crtc_state,
+ struct intel_connector *connector)
{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_display *display = to_intel_display(intel_dp);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
u16 y_granularity = 0;
+ u16 sink_y_granularity = crtc_state->has_panel_replay ?
+ connector->dp.panel_replay_caps.su_y_granularity :
+ connector->dp.psr_caps.su_y_granularity;
+ u16 sink_w_granularity = crtc_state->has_panel_replay ?
+ connector->dp.panel_replay_caps.su_w_granularity :
+ connector->dp.psr_caps.su_w_granularity;
/* PSR2 HW only send full lines so we only need to validate the width */
- if (crtc_hdisplay % intel_dp->psr.su_w_granularity)
+ if (crtc_hdisplay % sink_w_granularity)
return false;
- if (crtc_vdisplay % intel_dp->psr.su_y_granularity)
+ if (crtc_vdisplay % sink_y_granularity)
return false;
/* HW tracking is only aligned to 4 lines */
if (!crtc_state->enable_psr2_sel_fetch)
- return intel_dp->psr.su_y_granularity == 4;
+ return sink_y_granularity == 4;
/*
* adl_p and mtl platforms have 1 line granularity.
@@ -1330,11 +1323,11 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp,
* to match sink requirement if multiple of 4.
*/
if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14)
- y_granularity = intel_dp->psr.su_y_granularity;
- else if (intel_dp->psr.su_y_granularity <= 2)
+ y_granularity = sink_y_granularity;
+ else if (sink_y_granularity <= 2)
y_granularity = 4;
- else if ((intel_dp->psr.su_y_granularity % 4) == 0)
- y_granularity = intel_dp->psr.su_y_granularity;
+ else if ((sink_y_granularity % 4) == 0)
+ y_granularity = sink_y_granularity;
if (y_granularity == 0 || crtc_vdisplay % y_granularity)
return false;
@@ -1372,16 +1365,18 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d
}
static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp,
+ struct drm_connector_state *conn_state,
const struct drm_display_mode *adjusted_mode)
{
struct intel_display *display = to_intel_display(intel_dp);
- int psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ int psr_setup_time = drm_dp_psr_setup_time(connector->dp.psr_caps.dpcd);
int entry_setup_frames = 0;
if (psr_setup_time < 0) {
drm_dbg_kms(display->drm,
"PSR condition failed: Invalid PSR setup time (0x%02x)\n",
- intel_dp->psr_dpcd[1]);
+ connector->dp.psr_caps.dpcd[1]);
return -ETIME;
}
@@ -1522,14 +1517,16 @@ static bool alpm_config_valid(struct intel_dp *intel_dp,
}
static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state)
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
int psr_max_h = 0, psr_max_v = 0, max_bpp = 0;
- if (!intel_dp->psr.sink_psr2_support || display->params.enable_psr == 1)
+ if (!connector->dp.psr_caps.su_support || display->params.enable_psr == 1)
return false;
/* JSL and EHL only supports eDP 1.3 */
@@ -1621,9 +1618,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
return true;
}
-static bool intel_sel_update_config_valid(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state)
+static bool intel_sel_update_config_valid(struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_display *display = to_intel_display(intel_dp);
if (HAS_PSR2_SEL_FETCH(display) &&
@@ -1640,7 +1639,8 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp,
goto unsupported;
}
- if (!crtc_state->has_panel_replay && !intel_psr2_config_valid(intel_dp, crtc_state))
+ if (!crtc_state->has_panel_replay && !intel_psr2_config_valid(intel_dp, crtc_state,
+ conn_state))
goto unsupported;
if (!_compute_psr2_sdp_prior_scanline_indication(intel_dp, crtc_state)) {
@@ -1653,11 +1653,11 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp,
if (DISPLAY_VER(display) < 14)
goto unsupported;
- if (!intel_dp->psr.sink_panel_replay_su_support)
+ if (!connector->dp.panel_replay_caps.su_support)
goto unsupported;
if (intel_dsc_enabled_on_link(crtc_state) &&
- intel_dp->psr.sink_panel_replay_dsc_support !=
+ connector->dp.panel_replay_caps.dsc_support !=
INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE) {
drm_dbg_kms(display->drm,
"Selective update with Panel Replay not enabled because it's not supported with DSC\n");
@@ -1671,14 +1671,14 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp,
goto unsupported;
}
- if (!psr2_granularity_check(intel_dp, crtc_state)) {
+ if (!psr2_granularity_check(crtc_state, connector)) {
drm_dbg_kms(display->drm,
"Selective update not enabled, SU granularity not compatible\n");
goto unsupported;
}
- crtc_state->enable_psr2_su_region_et =
- psr2_su_region_et_valid(intel_dp, crtc_state->has_panel_replay);
+ crtc_state->enable_psr2_su_region_et = psr2_su_region_et_valid(connector,
+ crtc_state->has_panel_replay);
return true;
@@ -1688,7 +1688,8 @@ unsupported:
}
static bool _psr_compute_config(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state)
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
struct intel_display *display = to_intel_display(intel_dp);
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
@@ -1703,7 +1704,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp,
if (crtc_state->vrr.enable)
return false;
- entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode);
+ entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, conn_state, adjusted_mode);
if (entry_setup_frames >= 0) {
intel_dp->psr.entry_setup_frames = entry_setup_frames;
@@ -1717,19 +1718,33 @@ static bool _psr_compute_config(struct intel_dp *intel_dp,
return true;
}
-static bool
-_panel_replay_compute_config(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state)
+static inline bool compute_link_off_after_as_sdp_when_pr_active(struct intel_connector *connector)
+{
+ return (connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
+ DP_PANEL_REPLAY_LINK_OFF_SUPPORTED_IN_PR_AFTER_ADAPTIVE_SYNC_SDP);
+}
+
+static inline bool compute_disable_as_sdp_when_pr_active(struct intel_connector *connector)
+{
+ return !(connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
+ DP_PANEL_REPLAY_ASYNC_VIDEO_TIMING_NOT_SUPPORTED_IN_PR);
+}
+
+static bool _panel_replay_compute_config(struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state)
{
- struct intel_display *display = to_intel_display(intel_dp);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_display *display = to_intel_display(intel_dp);
struct intel_hdcp *hdcp = &connector->hdcp;
if (!CAN_PANEL_REPLAY(intel_dp))
return false;
+ if (!connector->dp.panel_replay_caps.support)
+ return false;
+
if (!panel_replay_global_enabled(intel_dp)) {
drm_dbg_kms(display->drm, "Panel Replay disabled by flag\n");
return false;
@@ -1742,13 +1757,16 @@ _panel_replay_compute_config(struct intel_dp *intel_dp,
}
if (intel_dsc_enabled_on_link(crtc_state) &&
- intel_dp->psr.sink_panel_replay_dsc_support ==
+ connector->dp.panel_replay_caps.dsc_support ==
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED) {
drm_dbg_kms(display->drm,
"Panel Replay not enabled because it's not supported with DSC\n");
return false;
}
+ crtc_state->link_off_after_as_sdp_when_pr_active = compute_link_off_after_as_sdp_when_pr_active(connector);
+ crtc_state->disable_as_sdp_when_pr_active = compute_disable_as_sdp_when_pr_active(connector);
+
if (!intel_dp_is_edp(intel_dp))
return true;
@@ -1824,6 +1842,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
struct drm_connector_state *conn_state)
{
struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
if (!psr_global_enabled(intel_dp)) {
@@ -1855,18 +1874,16 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
}
/* Only used for state verification. */
- crtc_state->panel_replay_dsc_support = intel_dp->psr.sink_panel_replay_dsc_support;
- crtc_state->has_panel_replay = _panel_replay_compute_config(intel_dp,
- crtc_state,
- conn_state);
+ crtc_state->panel_replay_dsc_support = connector->dp.panel_replay_caps.dsc_support;
+ crtc_state->has_panel_replay = _panel_replay_compute_config(crtc_state, conn_state);
crtc_state->has_psr = crtc_state->has_panel_replay ? true :
- _psr_compute_config(intel_dp, crtc_state);
+ _psr_compute_config(intel_dp, crtc_state, conn_state);
if (!crtc_state->has_psr)
return;
- crtc_state->has_sel_update = intel_sel_update_config_valid(intel_dp, crtc_state);
+ crtc_state->has_sel_update = intel_sel_update_config_valid(crtc_state, conn_state);
}
void intel_psr_get_config(struct intel_encoder *encoder,
@@ -2701,7 +2718,7 @@ intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
struct drm_rect inter;
- if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+ if (new_plane_state->hw.crtc != crtc_state->uapi.crtc)
continue;
if (plane->id != PLANE_CURSOR)
@@ -2734,7 +2751,7 @@ static bool psr2_sel_fetch_plane_state_supported(const struct intel_plane_state
if (plane_state->uapi.dst.y1 < 0 ||
plane_state->uapi.dst.x1 < 0 ||
plane_state->scaler_id >= 0 ||
- plane_state->uapi.rotation != DRM_MODE_ROTATE_0)
+ plane_state->hw.rotation != DRM_MODE_ROTATE_0)
return false;
return true;
@@ -2749,7 +2766,8 @@ static bool psr2_sel_fetch_plane_state_supported(const struct intel_plane_state
*/
static bool psr2_sel_fetch_pipe_state_supported(const struct intel_crtc_state *crtc_state)
{
- if (crtc_state->scaler_state.scaler_id >= 0)
+ if (crtc_state->scaler_state.scaler_id >= 0 ||
+ crtc_state->async_flip_planes)
return false;
return true;
@@ -2838,7 +2856,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct drm_rect src, damaged_area = { .x1 = 0, .y1 = -1,
.x2 = INT_MAX };
- if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+ if (new_plane_state->hw.crtc != crtc_state->uapi.crtc)
continue;
if (!new_plane_state->uapi.visible &&
@@ -2937,7 +2955,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct drm_rect *sel_fetch_area, inter;
struct intel_plane *linked = new_plane_state->planar_linked_plane;
- if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc ||
+ if (new_plane_state->hw.crtc != crtc_state->uapi.crtc ||
!new_plane_state->uapi.visible)
continue;
@@ -2992,9 +3010,9 @@ skip_sel_fetch_set_loop:
return 0;
}
-void intel_psr2_panic_force_full_update(struct intel_display *display,
- struct intel_crtc_state *crtc_state)
+void intel_psr2_panic_force_full_update(const struct intel_crtc_state *crtc_state)
{
+ struct intel_display *display = to_intel_display(crtc_state);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 val = man_trk_ctl_enable_bit_get(display);
@@ -4109,24 +4127,22 @@ psr_source_status(struct intel_dp *intel_dp, struct seq_file *m)
seq_printf(m, "Source PSR/PanelReplay status: %s [0x%08x]\n", status, val);
}
-static void intel_psr_sink_capability(struct intel_dp *intel_dp,
+static void intel_psr_sink_capability(struct intel_connector *connector,
struct seq_file *m)
{
- struct intel_psr *psr = &intel_dp->psr;
-
seq_printf(m, "Sink support: PSR = %s",
- str_yes_no(psr->sink_support));
+ str_yes_no(connector->dp.psr_caps.support));
- if (psr->sink_support)
- seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
- if (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED)
+ if (connector->dp.psr_caps.support)
+ seq_printf(m, " [0x%02x]", connector->dp.psr_caps.dpcd[0]);
+ if (connector->dp.psr_caps.dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED)
seq_printf(m, " (Early Transport)");
- seq_printf(m, ", Panel Replay = %s", str_yes_no(psr->sink_panel_replay_support));
+ seq_printf(m, ", Panel Replay = %s", str_yes_no(connector->dp.panel_replay_caps.support));
seq_printf(m, ", Panel Replay Selective Update = %s",
- str_yes_no(psr->sink_panel_replay_su_support));
+ str_yes_no(connector->dp.panel_replay_caps.su_support));
seq_printf(m, ", Panel Replay DSC support = %s",
- panel_replay_dsc_support_str(psr->sink_panel_replay_dsc_support));
- if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
+ panel_replay_dsc_support_str(connector->dp.panel_replay_caps.dsc_support));
+ if (connector->dp.panel_replay_caps.dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT)
seq_printf(m, " (Early Transport)");
seq_printf(m, "\n");
@@ -4164,7 +4180,8 @@ static void intel_psr_print_mode(struct intel_dp *intel_dp,
seq_printf(m, " %s\n", psr->no_psr_reason);
}
-static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
+static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp,
+ struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
@@ -4173,9 +4190,9 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
bool enabled;
u32 val, psr2_ctl;
- intel_psr_sink_capability(intel_dp, m);
+ intel_psr_sink_capability(connector, m);
- if (!(psr->sink_support || psr->sink_panel_replay_support))
+ if (!(connector->dp.psr_caps.support || connector->dp.panel_replay_caps.support))
return 0;
wakeref = intel_display_rpm_get(display);
@@ -4289,7 +4306,7 @@ static int i915_edp_psr_status_show(struct seq_file *m, void *data)
if (!intel_dp)
return -ENODEV;
- return intel_psr_status(m, intel_dp);
+ return intel_psr_status(m, intel_dp, intel_dp->attached_connector);
}
DEFINE_SHOW_ATTRIBUTE(i915_edp_psr_status);
@@ -4423,7 +4440,7 @@ static int i915_psr_status_show(struct seq_file *m, void *data)
struct intel_connector *connector = m->private;
struct intel_dp *intel_dp = intel_attached_dp(connector);
- return intel_psr_status(m, intel_dp);
+ return intel_psr_status(m, intel_dp, connector);
}
DEFINE_SHOW_ATTRIBUTE(i915_psr_status);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index 620b35928832..b41dc4d44ff2 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -28,7 +28,7 @@ struct intel_plane_state;
bool intel_encoder_can_psr(struct intel_encoder *encoder);
bool intel_psr_needs_aux_io_power(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
-void intel_psr_init_dpcd(struct intel_dp *intel_dp);
+void intel_psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector);
void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp);
void intel_psr_pre_plane_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
@@ -59,8 +59,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_psr2_program_trans_man_trk_ctl(struct intel_dsb *dsb,
const struct intel_crtc_state *crtc_state);
-void intel_psr2_panic_force_full_update(struct intel_display *display,
- struct intel_crtc_state *crtc_state);
+void intel_psr2_panic_force_full_update(const struct intel_crtc_state *crtc_state);
void intel_psr_pause(struct intel_dp *intel_dp);
void intel_psr_resume(struct intel_dp *intel_dp);
bool intel_psr_needs_vblank_notification(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/soc/intel_rom.c b/drivers/gpu/drm/i915/display/intel_rom.c
index 2f17dc856e7f..2f17dc856e7f 100644
--- a/drivers/gpu/drm/i915/soc/intel_rom.c
+++ b/drivers/gpu/drm/i915/display/intel_rom.c
diff --git a/drivers/gpu/drm/i915/soc/intel_rom.h b/drivers/gpu/drm/i915/display/intel_rom.h
index 4e59a375787e..4e59a375787e 100644
--- a/drivers/gpu/drm/i915/soc/intel_rom.h
+++ b/drivers/gpu/drm/i915/display/intel_rom.h
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 69b6873a6044..6a65f92e8a03 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -462,7 +462,7 @@ vlv_sprite_get_hw_state(struct intel_plane *plane,
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
enum plane_id plane_id = plane->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
@@ -893,7 +893,7 @@ ivb_sprite_get_hw_state(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
@@ -1233,7 +1233,7 @@ g4x_sprite_get_hw_state(struct intel_plane *plane,
{
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
@@ -1567,6 +1567,7 @@ static const struct drm_plane_funcs g4x_sprite_funcs = {
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = g4x_sprite_format_mod_supported,
+ .format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static const struct drm_plane_funcs snb_sprite_funcs = {
@@ -1576,6 +1577,7 @@ static const struct drm_plane_funcs snb_sprite_funcs = {
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = snb_sprite_format_mod_supported,
+ .format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static const struct drm_plane_funcs vlv_sprite_funcs = {
@@ -1585,6 +1587,7 @@ static const struct drm_plane_funcs vlv_sprite_funcs = {
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = vlv_sprite_format_mod_supported,
+ .format_mod_supported_async = intel_plane_format_mod_supported_async,
};
struct intel_plane *
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 1e21fd02685d..064f572bbc85 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -51,7 +51,7 @@ struct intel_tc_port {
const struct intel_tc_phy_ops *phy_ops;
struct mutex lock; /* protects the TypeC port mode */
- intel_wakeref_t lock_wakeref;
+ struct ref_tracker *lock_wakeref;
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
enum intel_display_power_domain lock_power_domain;
#endif
@@ -182,7 +182,7 @@ bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port)
intel_display_power_legacy_aux_domain(display, dig_port->aux_ch);
}
-static intel_wakeref_t
+static struct ref_tracker *
__tc_cold_block(struct intel_tc_port *tc, enum intel_display_power_domain *domain)
{
struct intel_display *display = to_intel_display(tc->dig_port);
@@ -192,11 +192,11 @@ __tc_cold_block(struct intel_tc_port *tc, enum intel_display_power_domain *domai
return intel_display_power_get(display, *domain);
}
-static intel_wakeref_t
+static struct ref_tracker *
tc_cold_block(struct intel_tc_port *tc)
{
enum intel_display_power_domain domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
wakeref = __tc_cold_block(tc, &domain);
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
@@ -207,7 +207,7 @@ tc_cold_block(struct intel_tc_port *tc)
static void
__tc_cold_unblock(struct intel_tc_port *tc, enum intel_display_power_domain domain,
- intel_wakeref_t wakeref)
+ struct ref_tracker *wakeref)
{
struct intel_display *display = to_intel_display(tc->dig_port);
@@ -215,7 +215,7 @@ __tc_cold_unblock(struct intel_tc_port *tc, enum intel_display_power_domain doma
}
static void
-tc_cold_unblock(struct intel_tc_port *tc, intel_wakeref_t wakeref)
+tc_cold_unblock(struct intel_tc_port *tc, struct ref_tracker *wakeref)
{
struct intel_display __maybe_unused *display = to_intel_display(tc->dig_port);
enum intel_display_power_domain domain = tc_phy_cold_off_domain(tc);
@@ -269,10 +269,9 @@ assert_tc_port_power_enabled(struct intel_tc_port *tc)
static u32 get_lane_mask(struct intel_tc_port *tc)
{
struct intel_display *display = to_intel_display(tc->dig_port);
- intel_wakeref_t wakeref;
u32 lane_mask;
- with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref)
+ with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE)
lane_mask = intel_de_read(display, PORT_TX_DFLEXDPSP(tc->phy_fia));
drm_WARN_ON(display->drm, lane_mask == 0xffffffff);
@@ -296,7 +295,6 @@ get_pin_assignment(struct intel_tc_port *tc)
struct intel_display *display = to_intel_display(tc->dig_port);
enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base);
enum intel_tc_pin_assignment pin_assignment;
- intel_wakeref_t wakeref;
i915_reg_t reg;
u32 mask;
u32 val;
@@ -312,7 +310,7 @@ get_pin_assignment(struct intel_tc_port *tc)
mask = DP_PIN_ASSIGNMENT_MASK(tc->phy_fia_idx);
}
- with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref)
+ with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE)
val = intel_de_read(display, reg);
drm_WARN_ON(display->drm, val == 0xffffffff);
@@ -527,12 +525,11 @@ static u32 icl_tc_phy_hpd_live_status(struct intel_tc_port *tc)
struct intel_display *display = to_intel_display(tc->dig_port);
struct intel_digital_port *dig_port = tc->dig_port;
u32 isr_bit = display->hotplug.pch_hpd[dig_port->base.hpd_pin];
- intel_wakeref_t wakeref;
u32 fia_isr;
u32 pch_isr;
u32 mask = 0;
- with_intel_display_power(display, tc_phy_cold_off_domain(tc), wakeref) {
+ with_intel_display_power(display, tc_phy_cold_off_domain(tc)) {
fia_isr = intel_de_read(display, PORT_TX_DFLEXDPSP(tc->phy_fia));
pch_isr = intel_de_read(display, SDEISR);
}
@@ -628,7 +625,7 @@ static bool icl_tc_phy_is_owned(struct intel_tc_port *tc)
static void icl_tc_phy_get_hw_state(struct intel_tc_port *tc)
{
enum intel_display_power_domain domain;
- intel_wakeref_t tc_cold_wref;
+ struct ref_tracker *tc_cold_wref;
tc_cold_wref = __tc_cold_block(tc, &domain);
@@ -774,10 +771,9 @@ tgl_tc_phy_cold_off_domain(struct intel_tc_port *tc)
static void tgl_tc_phy_init(struct intel_tc_port *tc)
{
struct intel_display *display = to_intel_display(tc->dig_port);
- intel_wakeref_t wakeref;
u32 val;
- with_intel_display_power(display, tc_phy_cold_off_domain(tc), wakeref)
+ with_intel_display_power(display, tc_phy_cold_off_domain(tc))
val = intel_de_read(display, PORT_TX_DFLEXDPSP(FIA1));
drm_WARN_ON(display->drm, val == 0xffffffff);
@@ -819,12 +815,11 @@ static u32 adlp_tc_phy_hpd_live_status(struct intel_tc_port *tc)
enum hpd_pin hpd_pin = dig_port->base.hpd_pin;
u32 cpu_isr_bits = display->hotplug.hpd[hpd_pin];
u32 pch_isr_bit = display->hotplug.pch_hpd[hpd_pin];
- intel_wakeref_t wakeref;
u32 cpu_isr;
u32 pch_isr;
u32 mask = 0;
- with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) {
+ with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE) {
cpu_isr = intel_de_read(display, GEN11_DE_HPD_ISR);
pch_isr = intel_de_read(display, SDEISR);
}
@@ -897,7 +892,7 @@ static void adlp_tc_phy_get_hw_state(struct intel_tc_port *tc)
struct intel_display *display = to_intel_display(tc->dig_port);
enum intel_display_power_domain port_power_domain =
tc_port_power_domain(tc);
- intel_wakeref_t port_wakeref;
+ struct ref_tracker *port_wakeref;
port_wakeref = intel_display_power_get(display, port_power_domain);
@@ -916,7 +911,7 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)
struct intel_display *display = to_intel_display(tc->dig_port);
enum intel_display_power_domain port_power_domain =
tc_port_power_domain(tc);
- intel_wakeref_t port_wakeref;
+ struct ref_tracker *port_wakeref;
if (tc->mode == TC_PORT_TBT_ALT) {
tc->lock_wakeref = tc_cold_block(tc);
@@ -968,7 +963,7 @@ static void adlp_tc_phy_disconnect(struct intel_tc_port *tc)
struct intel_display *display = to_intel_display(tc->dig_port);
enum intel_display_power_domain port_power_domain =
tc_port_power_domain(tc);
- intel_wakeref_t port_wakeref;
+ struct ref_tracker *port_wakeref;
port_wakeref = intel_display_power_get(display, port_power_domain);
@@ -1015,12 +1010,11 @@ static u32 xelpdp_tc_phy_hpd_live_status(struct intel_tc_port *tc)
enum hpd_pin hpd_pin = dig_port->base.hpd_pin;
u32 pica_isr_bits = display->hotplug.hpd[hpd_pin];
u32 pch_isr_bit = display->hotplug.pch_hpd[hpd_pin];
- intel_wakeref_t wakeref;
u32 pica_isr;
u32 pch_isr;
u32 mask = 0;
- with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) {
+ with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE) {
pica_isr = intel_de_read(display, PICAINTERRUPT_ISR);
pch_isr = intel_de_read(display, SDEISR);
}
@@ -1175,7 +1169,7 @@ static bool xelpdp_tc_phy_is_owned(struct intel_tc_port *tc)
static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc)
{
struct intel_display *display = to_intel_display(tc->dig_port);
- intel_wakeref_t tc_cold_wref;
+ struct ref_tracker *tc_cold_wref;
enum intel_display_power_domain domain;
tc_cold_wref = __tc_cold_block(tc, &domain);
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index 70e31520c560..57fda5824c9c 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -554,7 +554,8 @@ struct child_device_config {
u8 dvo_function;
u8 dp_usb_type_c:1; /* 195+ */
u8 tbt:1; /* 209+ */
- u8 flags2_reserved:2; /* 195+ */
+ u8 dedicated_external:1; /* 264+ */
+ u8 dyn_port_over_tc:1; /* 264+ */
u8 dp_port_trace_length:4; /* 209+ */
u8 dp_gpio_index; /* 195+ */
u16 dp_gpio_pin_num; /* 195+ */
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index 0e727fc5e80c..ad5fe841e4b3 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -999,7 +999,7 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
u32 dss_ctl1, dss_ctl2;
if (!intel_dsc_source_support(crtc_state))
diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c
index 6e125564db34..c45c4bbc3f95 100644
--- a/drivers/gpu/drm/i915/display/intel_vga.c
+++ b/drivers/gpu/drm/i915/display/intel_vga.c
@@ -9,12 +9,12 @@
#include <drm/drm_device.h>
#include <drm/drm_print.h>
+#include <drm/intel/i915_drm.h>
#include <video/vga.h>
-#include "soc/intel_gmch.h"
-
#include "intel_de.h"
#include "intel_display.h"
+#include "intel_display_types.h"
#include "intel_vga.h"
#include "intel_vga_regs.h"
@@ -95,6 +95,46 @@ void intel_vga_reset_io_mem(struct intel_display *display)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
}
+static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_decode)
+{
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
+ unsigned int reg = DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
+ u16 gmch_ctrl;
+
+ if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), reg, &gmch_ctrl)) {
+ drm_err(display->drm, "failed to read control word\n");
+ return -EIO;
+ }
+
+ if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
+ return 0;
+
+ if (enable_decode)
+ gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
+ else
+ gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
+
+ if (pci_bus_write_config_word(pdev->bus, PCI_DEVFN(0, 0), reg, gmch_ctrl)) {
+ drm_err(display->drm, "failed to write control word\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
+{
+ struct intel_display *display = to_intel_display(pdev);
+
+ intel_gmch_vga_set_state(display, enable_decode);
+
+ if (enable_decode)
+ return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+ else
+ return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
+
int intel_vga_register(struct intel_display *display)
{
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index ee8e24497d2c..b3d41705448a 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -9,7 +9,6 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
-#include "pxp/intel_pxp.h"
#include "intel_bo.h"
#include "intel_color.h"
#include "intel_color_pipeline.h"
@@ -22,7 +21,7 @@
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
-#include "intel_panic.h"
+#include "intel_parent.h"
#include "intel_plane.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
@@ -597,7 +596,7 @@ static u32 tgl_plane_min_alignment(struct intel_plane *plane,
* Figure out what's going on here...
*/
if (display->platform.alderlake_p &&
- intel_plane_can_async_flip(plane, fb->format->format, fb->modifier))
+ intel_plane_can_async_flip(plane, fb->format, fb->modifier))
return mult * 16 * 1024;
switch (fb->modifier) {
@@ -941,7 +940,7 @@ skl_plane_get_hw_state(struct intel_plane *plane,
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
enum plane_id plane_id = plane->id;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
@@ -1603,7 +1602,7 @@ icl_plane_update_noarm(struct intel_dsb *dsb,
}
/* FLAT CCS doesn't need to program AUX_DIST */
- if (HAS_AUX_CCS(display))
+ if (HAS_AUX_DIST(display))
intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
skl_plane_aux_dist(plane_state, color_plane));
@@ -2308,7 +2307,7 @@ static void check_protection(struct intel_plane_state *plane_state)
if (DISPLAY_VER(display) < 11)
return;
- plane_state->decrypt = intel_pxp_key_check(obj, false) == 0;
+ plane_state->decrypt = intel_bo_key_check(obj) == 0;
plane_state->force_black = intel_bo_is_protected(obj) &&
!plane_state->decrypt;
}
@@ -2462,7 +2461,7 @@ static struct intel_fbc *skl_plane_fbc(struct intel_display *display,
enum intel_fbc_id fbc_id = skl_fbc_id_for_pipe(pipe);
if (skl_plane_has_fbc(display, fbc_id, plane_id))
- return display->fbc[fbc_id];
+ return display->fbc.instances[fbc_id];
else
return NULL;
}
@@ -2973,12 +2972,6 @@ skl_universal_plane_create(struct intel_display *display,
else
caps = skl_plane_caps(display, pipe, plane_id);
- /* FIXME: xe has problems with AUX */
- if (!IS_ENABLED(I915) && HAS_AUX_CCS(display))
- caps &= ~(INTEL_PLANE_CAP_CCS_RC |
- INTEL_PLANE_CAP_CCS_RC_CC |
- INTEL_PLANE_CAP_CCS_MC);
-
modifiers = intel_fb_plane_get_modifiers(display, caps);
ret = drm_universal_plane_init(display->drm, &plane->base,
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index 54e9e0be019d..a6aab79812e5 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -8,7 +8,6 @@
#include <drm/drm_blend.h>
#include <drm/drm_print.h>
-#include "soc/intel_dram.h"
#include "i915_reg.h"
#include "i9xx_wm.h"
#include "intel_atomic.h"
@@ -23,6 +22,7 @@
#include "intel_display_rpm.h"
#include "intel_display_types.h"
#include "intel_display_utils.h"
+#include "intel_dram.h"
#include "intel_fb.h"
#include "intel_fixed.h"
#include "intel_flipq.h"
@@ -718,7 +718,7 @@ static void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
struct intel_display *display = to_intel_display(crtc);
enum intel_display_power_domain power_domain;
enum pipe pipe = crtc->pipe;
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum plane_id plane_id;
power_domain = POWER_DOMAIN_PIPE(pipe);
@@ -3125,7 +3125,7 @@ static bool skl_watermark_ipc_can_enable(struct intel_display *display)
if (display->platform.kabylake ||
display->platform.coffeelake ||
display->platform.cometlake) {
- const struct dram_info *dram_info = intel_dram_info(display->drm);
+ const struct dram_info *dram_info = intel_dram_info(display);
return dram_info->symmetric_memory;
}
@@ -3169,7 +3169,7 @@ static void increase_wm_latency(struct intel_display *display, int inc)
static bool need_16gb_dimm_wa(struct intel_display *display)
{
- const struct dram_info *dram_info = intel_dram_info(display->drm);
+ const struct dram_info *dram_info = intel_dram_info(display);
return (display->platform.skylake || display->platform.kabylake ||
display->platform.coffeelake || display->platform.cometlake ||
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index 19bdd8662359..d705af3bf8ba 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -936,7 +936,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- intel_wakeref_t wakeref;
+ struct ref_tracker *wakeref;
enum port port;
bool active = false;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
index 465ce94aee76..969f6ea2b855 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -348,12 +348,13 @@ struct drm_i915_gem_object {
*/
#define I915_BO_ALLOC_GPU_ONLY BIT(6)
#define I915_BO_ALLOC_CCS_AUX BIT(7)
+#define I915_BO_ALLOC_NOTHP BIT(8)
/*
* Object is allowed to retain its initial data and will not be cleared on first
* access if used along with I915_BO_ALLOC_USER. This is mainly to keep
* preallocated framebuffer data intact while transitioning it to i915drmfb.
*/
-#define I915_BO_PREALLOC BIT(8)
+#define I915_BO_PREALLOC BIT(9)
#define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \
I915_BO_ALLOC_VOLATILE | \
I915_BO_ALLOC_CPU_CLEAR | \
@@ -362,10 +363,11 @@ struct drm_i915_gem_object {
I915_BO_ALLOC_PM_EARLY | \
I915_BO_ALLOC_GPU_ONLY | \
I915_BO_ALLOC_CCS_AUX | \
+ I915_BO_ALLOC_NOTHP | \
I915_BO_PREALLOC)
-#define I915_BO_READONLY BIT(9)
-#define I915_TILING_QUIRK_BIT 10 /* unknown swizzling; do not release! */
-#define I915_BO_PROTECTED BIT(11)
+#define I915_BO_READONLY BIT(10)
+#define I915_TILING_QUIRK_BIT 11 /* unknown swizzling; do not release! */
+#define I915_BO_PROTECTED BIT(12)
/**
* @mem_flags - Mutable placement-related flags
*
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 26dda55a07ff..6ad1d6f99363 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -9,14 +9,16 @@
#include <linux/uio.h>
#include <drm/drm_cache.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_print.h>
#include "gem/i915_gem_region.h"
#include "i915_drv.h"
#include "i915_gem_object.h"
#include "i915_gem_tiling.h"
-#include "i915_gemfs.h"
#include "i915_scatterlist.h"
#include "i915_trace.h"
+#include "i915_utils.h"
/*
* Move folios to appropriate lru and release the batch, decrementing the
@@ -494,9 +496,11 @@ const struct drm_i915_gem_object_ops i915_gem_shmem_ops = {
static int __create_shmem(struct drm_i915_private *i915,
struct drm_gem_object *obj,
- resource_size_t size)
+ resource_size_t size,
+ unsigned int flags)
{
- unsigned long flags = VM_NORESERVE;
+ unsigned long shmem_flags = VM_NORESERVE;
+ struct vfsmount *huge_mnt;
struct file *filp;
drm_gem_private_object_init(&i915->drm, obj, size);
@@ -515,11 +519,12 @@ static int __create_shmem(struct drm_i915_private *i915,
if (BITS_PER_LONG == 64 && size > MAX_LFS_FILESIZE)
return -E2BIG;
- if (i915->mm.gemfs)
- filp = shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size,
- flags);
+ huge_mnt = drm_gem_get_huge_mnt(&i915->drm);
+ if (!(flags & I915_BO_ALLOC_NOTHP) && huge_mnt)
+ filp = shmem_file_setup_with_mnt(huge_mnt, "i915", size,
+ shmem_flags);
else
- filp = shmem_file_setup("i915", size, flags);
+ filp = shmem_file_setup("i915", size, shmem_flags);
if (IS_ERR(filp))
return PTR_ERR(filp);
@@ -548,7 +553,7 @@ static int shmem_object_init(struct intel_memory_region *mem,
gfp_t mask;
int ret;
- ret = __create_shmem(i915, &obj->base, size);
+ ret = __create_shmem(i915, &obj->base, size, flags);
if (ret)
return ret;
@@ -644,21 +649,40 @@ fail:
static int init_shmem(struct intel_memory_region *mem)
{
- i915_gemfs_init(mem->i915);
- intel_memory_region_set_name(mem, "system");
+ struct drm_i915_private *i915 = mem->i915;
- return 0; /* We have fallback to the kernel mnt if gemfs init failed. */
-}
+ /*
+ * By creating our own shmemfs mountpoint, we can pass in
+ * mount flags that better match our usecase.
+ *
+ * One example, although it is probably better with a per-file
+ * control, is selecting huge page allocations ("huge=within_size").
+ * However, we only do so on platforms which benefit from it, or to
+ * offset the overhead of iommu lookups, where with latter it is a net
+ * win even on platforms which would otherwise see some performance
+ * regressions such a slow reads issue on Broadwell and Skylake.
+ */
-static int release_shmem(struct intel_memory_region *mem)
-{
- i915_gemfs_fini(mem->i915);
- return 0;
+ if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915))
+ goto no_thp;
+
+ drm_gem_huge_mnt_create(&i915->drm, "within_size");
+ if (drm_gem_get_huge_mnt(&i915->drm))
+ drm_info(&i915->drm, "Using Transparent Hugepages\n");
+ else
+ drm_notice(&i915->drm,
+ "Transparent Hugepage support is recommended for optimal performance%s\n",
+ GRAPHICS_VER(i915) >= 11 ? " on this platform!" :
+ " when IOMMU is enabled!");
+
+ no_thp:
+ intel_memory_region_set_name(mem, "system");
+
+ return 0; /* We have fallback to the kernel mnt if huge mnt failed. */
}
static const struct intel_memory_region_ops shmem_region_ops = {
.init = init_shmem,
- .release = release_shmem,
.init_object = shmem_object_init,
};
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index f859c99f969b..c3e0b8da485c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -8,6 +8,7 @@
#include <drm/drm_mm.h>
#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
#include <drm/intel/i915_drm.h>
#include "gem/i915_gem_lmem.h"
@@ -64,8 +65,8 @@ static int __i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915,
return ret;
}
-int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
- unsigned int alignment, u64 start, u64 end)
+static int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
+ unsigned int alignment, u64 start, u64 end)
{
return __i915_gem_stolen_insert_node_in_range(node->i915, &node->node,
size, alignment,
@@ -82,8 +83,8 @@ static int __i915_gem_stolen_insert_node(struct drm_i915_private *i915,
U64_MAX);
}
-int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size,
- unsigned int alignment)
+static int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size,
+ unsigned int alignment)
{
return __i915_gem_stolen_insert_node(node->i915, &node->node, size, alignment);
}
@@ -96,7 +97,7 @@ static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915,
mutex_unlock(&i915->mm.stolen_lock);
}
-void i915_gem_stolen_remove_node(struct intel_stolen_node *node)
+static void i915_gem_stolen_remove_node(struct intel_stolen_node *node)
{
__i915_gem_stolen_remove_node(node->i915, &node->node);
}
@@ -1025,50 +1026,50 @@ bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj)
return obj->ops == &i915_gem_object_stolen_ops;
}
-bool i915_gem_stolen_initialized(struct drm_device *drm)
+static bool i915_gem_stolen_initialized(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
return drm_mm_initialized(&i915->mm.stolen);
}
-u64 i915_gem_stolen_area_address(struct drm_device *drm)
+static u64 i915_gem_stolen_area_address(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
return i915->dsm.stolen.start;
}
-u64 i915_gem_stolen_area_size(struct drm_device *drm)
+static u64 i915_gem_stolen_area_size(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
return resource_size(&i915->dsm.stolen);
}
-u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node)
+static u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node)
+{
+ return node->node.start;
+}
+
+static u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node)
{
struct drm_i915_private *i915 = node->i915;
return i915->dsm.stolen.start + i915_gem_stolen_node_offset(node);
}
-bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node)
+static bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node)
{
return drm_mm_node_allocated(&node->node);
}
-u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node)
-{
- return node->node.start;
-}
-
-u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node)
+static u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node)
{
return node->node.size;
}
-struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
+static struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
struct intel_stolen_node *node;
@@ -1082,7 +1083,22 @@ struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
return node;
}
-void i915_gem_stolen_node_free(const struct intel_stolen_node *node)
+static void i915_gem_stolen_node_free(const struct intel_stolen_node *node)
{
kfree(node);
}
+
+const struct intel_display_stolen_interface i915_display_stolen_interface = {
+ .insert_node_in_range = i915_gem_stolen_insert_node_in_range,
+ .insert_node = i915_gem_stolen_insert_node,
+ .remove_node = i915_gem_stolen_remove_node,
+ .initialized = i915_gem_stolen_initialized,
+ .node_allocated = i915_gem_stolen_node_allocated,
+ .node_offset = i915_gem_stolen_node_offset,
+ .area_address = i915_gem_stolen_area_address,
+ .area_size = i915_gem_stolen_area_size,
+ .node_address = i915_gem_stolen_node_address,
+ .node_size = i915_gem_stolen_node_size,
+ .node_alloc = i915_gem_stolen_node_alloc,
+ .node_free = i915_gem_stolen_node_free,
+};
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
index 7b0386002ed4..6db5262046a2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h
@@ -8,17 +8,9 @@
#include <linux/types.h>
-struct drm_device;
struct drm_i915_gem_object;
struct drm_i915_private;
-struct intel_stolen_node;
-
-int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size,
- unsigned alignment);
-int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
- unsigned alignment, u64 start,
- u64 end);
-void i915_gem_stolen_remove_node(struct intel_stolen_node *node);
+
struct intel_memory_region *
i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
u16 instance);
@@ -34,17 +26,6 @@ bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj);
#define I915_GEM_STOLEN_BIAS SZ_128K
-bool i915_gem_stolen_initialized(struct drm_device *drm);
-u64 i915_gem_stolen_area_address(struct drm_device *drm);
-u64 i915_gem_stolen_area_size(struct drm_device *drm);
-
-u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node);
-
-bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node);
-u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node);
-u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node);
-
-struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm);
-void i915_gem_stolen_node_free(const struct intel_stolen_node *node);
+extern const struct intel_display_stolen_interface i915_display_stolen_interface;
#endif /* __I915_GEM_STOLEN_H__ */
diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.c b/drivers/gpu/drm/i915/gem/i915_gemfs.c
deleted file mode 100644
index 1f1290214031..000000000000
--- a/drivers/gpu/drm/i915/gem/i915_gemfs.c
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2017 Intel Corporation
- */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/fs_context.h>
-
-#include <drm/drm_print.h>
-
-#include "i915_drv.h"
-#include "i915_gemfs.h"
-#include "i915_utils.h"
-
-void i915_gemfs_init(struct drm_i915_private *i915)
-{
- struct file_system_type *type;
- struct fs_context *fc;
- struct vfsmount *gemfs;
- int ret;
-
- /*
- * By creating our own shmemfs mountpoint, we can pass in
- * mount flags that better match our usecase.
- *
- * One example, although it is probably better with a per-file
- * control, is selecting huge page allocations ("huge=within_size").
- * However, we only do so on platforms which benefit from it, or to
- * offset the overhead of iommu lookups, where with latter it is a net
- * win even on platforms which would otherwise see some performance
- * regressions such a slow reads issue on Broadwell and Skylake.
- */
-
- if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915))
- return;
-
- if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
- goto err;
-
- type = get_fs_type("tmpfs");
- if (!type)
- goto err;
-
- fc = fs_context_for_mount(type, SB_KERNMOUNT);
- if (IS_ERR(fc))
- goto err;
- ret = vfs_parse_fs_string(fc, "source", "tmpfs");
- if (!ret)
- ret = vfs_parse_fs_string(fc, "huge", "within_size");
- if (!ret)
- gemfs = fc_mount_longterm(fc);
- put_fs_context(fc);
- if (ret)
- goto err;
-
- i915->mm.gemfs = gemfs;
- drm_info(&i915->drm, "Using Transparent Hugepages\n");
- return;
-
-err:
- drm_notice(&i915->drm,
- "Transparent Hugepage support is recommended for optimal performance%s\n",
- GRAPHICS_VER(i915) >= 11 ? " on this platform!" :
- " when IOMMU is enabled!");
-}
-
-void i915_gemfs_fini(struct drm_i915_private *i915)
-{
- kern_unmount(i915->mm.gemfs);
-}
diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.h b/drivers/gpu/drm/i915/gem/i915_gemfs.h
deleted file mode 100644
index 16d4333c9a4e..000000000000
--- a/drivers/gpu/drm/i915/gem/i915_gemfs.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2017 Intel Corporation
- */
-
-#ifndef __I915_GEMFS_H__
-#define __I915_GEMFS_H__
-
-struct drm_i915_private;
-
-void i915_gemfs_init(struct drm_i915_private *i915);
-void i915_gemfs_fini(struct drm_i915_private *i915);
-
-#endif
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
index bd08605a1611..02e9bf87f654 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
@@ -1316,7 +1316,7 @@ typedef struct drm_i915_gem_object *
static inline bool igt_can_allocate_thp(struct drm_i915_private *i915)
{
- return i915->mm.gemfs && has_transparent_hugepage();
+ return !!drm_gem_get_huge_mnt(&i915->drm);
}
static struct drm_i915_gem_object *
@@ -1761,7 +1761,6 @@ static int igt_tmpfs_fallback(void *arg)
struct drm_i915_private *i915 = arg;
struct i915_address_space *vm;
struct i915_gem_context *ctx;
- struct vfsmount *gemfs = i915->mm.gemfs;
struct drm_i915_gem_object *obj;
struct i915_vma *vma;
struct file *file;
@@ -1779,15 +1778,8 @@ static int igt_tmpfs_fallback(void *arg)
}
vm = i915_gem_context_get_eb_vm(ctx);
- /*
- * Make sure that we don't burst into a ball of flames upon falling back
- * to tmpfs, which we rely on if on the off-chance we encounter a failure
- * when setting up gemfs.
- */
-
- i915->mm.gemfs = NULL;
-
- obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
+ obj = i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_SMEM],
+ PAGE_SIZE, 0, I915_BO_ALLOC_NOTHP);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
goto out_restore;
@@ -1819,7 +1811,6 @@ static int igt_tmpfs_fallback(void *arg)
out_put:
i915_gem_object_put(obj);
out_restore:
- i915->mm.gemfs = gemfs;
i915_vm_put(vm);
out:
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index b721bbd23356..98a3a7a9de50 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -963,9 +963,6 @@ int intel_engines_init_mmio(struct intel_gt *gt)
drm_WARN_ON(&i915->drm, engine_mask &
GENMASK(BITS_PER_TYPE(mask) - 1, I915_NUM_ENGINES));
- if (i915_inject_probe_failure(i915))
- return -ENODEV;
-
for (class = 0; class < MAX_ENGINE_CLASS + 1; ++class) {
setup_logical_ids(gt, logical_ids, class);
@@ -1007,6 +1004,7 @@ cleanup:
intel_engines_free(gt);
return err;
}
+ALLOW_ERROR_INJECTION(intel_engines_init_mmio, ERRNO);
void intel_engine_init_execlists(struct intel_engine_cs *engine)
{
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index 3d3b1ba76e2b..ac527d878820 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -686,10 +686,6 @@ int intel_gt_init(struct intel_gt *gt)
{
int err;
- err = i915_inject_probe_error(gt->i915, -ENODEV);
- if (err)
- return err;
-
intel_gt_init_workarounds(gt);
/*
@@ -740,10 +736,6 @@ int intel_gt_init(struct intel_gt *gt)
if (err)
goto err_gt;
- err = i915_inject_probe_error(gt->i915, -EIO);
- if (err)
- goto err_gt;
-
intel_uc_init_late(&gt->uc);
intel_migrate_init(&gt->migrate, gt);
@@ -766,6 +758,7 @@ out_fw:
intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
return err;
}
+ALLOW_ERROR_INJECTION(intel_gt_init, ERRNO);
void intel_gt_driver_remove(struct intel_gt *gt)
{
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
index c90b35881a26..aecd120972ea 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
@@ -4,12 +4,12 @@
*/
#include "i915_drv.h"
+#include "i915_freq.h"
#include "i915_reg.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
#include "intel_gt_print.h"
#include "intel_gt_regs.h"
-#include "soc/intel_dram.h"
static u32 read_reference_ts_freq(struct intel_uncore *uncore)
{
@@ -148,7 +148,7 @@ static u32 gen4_read_clock_frequency(struct intel_uncore *uncore)
*
* Testing on actual hardware has shown there is no /16.
*/
- return DIV_ROUND_CLOSEST(intel_fsb_freq(uncore->i915), 4) * 1000;
+ return DIV_ROUND_CLOSEST(i9xx_fsb_freq(uncore->i915), 4) * 1000;
}
static u32 read_clock_frequency(struct intel_uncore *uncore)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_print.h b/drivers/gpu/drm/i915/gt/intel_gt_print.h
index 7fdc78c79273..48f0afd05fd8 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_print.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_print.h
@@ -36,10 +36,7 @@
#define gt_probe_error(_gt, _fmt, ...) \
do { \
- if (i915_error_injected()) \
- gt_dbg(_gt, _fmt, ##__VA_ARGS__); \
- else \
- gt_err(_gt, _fmt, ##__VA_ARGS__); \
+ gt_err(_gt, _fmt, ##__VA_ARGS__); \
} while (0)
#define gt_WARN(_gt, _condition, _fmt, ...) \
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index e8927ad49142..d36e543e98df 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1911,10 +1911,6 @@ retry:
__i915_gem_object_flush_map(wa_ctx->vma->obj, 0, batch_ptr - batch);
__i915_gem_object_release_map(wa_ctx->vma->obj);
- /* Verify that we can handle failure to setup the wa_ctx */
- if (!err)
- err = i915_inject_probe_error(engine->i915, -ENODEV);
-
err_unpin:
if (err)
i915_vma_unpin(wa_ctx->vma);
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index b01c837ab646..90b7eee78f1f 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -6,12 +6,13 @@
#include <linux/string_helpers.h>
#include <drm/intel/i915_drm.h>
+#include <drm/intel/display_parent_interface.h>
#include "display/intel_display_rps.h"
#include "display/vlv_clock.h"
-#include "soc/intel_dram.h"
#include "i915_drv.h"
+#include "i915_freq.h"
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
@@ -284,8 +285,8 @@ static void gen5_rps_init(struct intel_rps *rps)
u32 rgvmodectl;
int c_m, i;
- fsb_freq = intel_fsb_freq(i915);
- mem_freq = intel_mem_freq(i915);
+ fsb_freq = ilk_fsb_freq(i915);
+ mem_freq = ilk_mem_freq(i915);
if (fsb_freq <= 3200000)
c_m = 0;
@@ -2914,6 +2915,39 @@ bool i915_gpu_turbo_disable(void)
}
EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
+static void boost_if_not_started(struct dma_fence *fence)
+{
+ struct i915_request *rq;
+
+ if (!dma_fence_is_i915(fence))
+ return;
+
+ rq = to_request(fence);
+
+ if (!i915_request_started(rq))
+ intel_rps_boost(rq);
+}
+
+static void mark_interactive(struct drm_device *drm, bool interactive)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+
+ intel_rps_mark_interactive(&to_gt(i915)->rps, interactive);
+}
+
+static void ilk_irq_handler(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+
+ gen5_rps_irq_handler(&to_gt(i915)->rps);
+}
+
+const struct intel_display_rps_interface i915_display_rps_interface = {
+ .boost_if_not_started = boost_if_not_started,
+ .mark_interactive = mark_interactive,
+ .ilk_irq_handler = ilk_irq_handler,
+};
+
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftest_rps.c"
#include "selftest_slpc.c"
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.h b/drivers/gpu/drm/i915/gt/intel_rps.h
index 92fb01f5a452..5dbcebd7d4a5 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.h
+++ b/drivers/gpu/drm/i915/gt/intel_rps.h
@@ -128,4 +128,6 @@ static inline void intel_rps_clear_timer(struct intel_rps *rps)
clear_bit(INTEL_RPS_TIMER, &rps->flags);
}
+extern const struct intel_display_rps_interface i915_display_rps_interface;
+
#endif /* INTEL_RPS_H */
diff --git a/drivers/gpu/drm/i915/gt/intel_wopcm.c b/drivers/gpu/drm/i915/gt/intel_wopcm.c
index 1b26ff6488b3..602e088fe045 100644
--- a/drivers/gpu/drm/i915/gt/intel_wopcm.c
+++ b/drivers/gpu/drm/i915/gt/intel_wopcm.c
@@ -253,9 +253,6 @@ void intel_wopcm_init(struct intel_wopcm *wopcm)
GEM_BUG_ON(huc_fw_size >= wopcm_size);
GEM_BUG_ON(ctx_rsvd + WOPCM_RESERVED_SIZE >= wopcm_size);
- if (i915_inject_probe_failure(i915))
- return;
-
if (__wopcm_regs_locked(gt->uncore, &guc_wopcm_base, &guc_wopcm_size)) {
drm_dbg(&i915->drm, "GuC WOPCM is already locked [%uK, %uK)\n",
guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
index 2c651ec024ef..f1e53312ed90 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
@@ -266,10 +266,6 @@ int intel_guc_ct_init(struct intel_guc_ct *ct)
u32 *cmds;
int err;
- err = i915_inject_probe_error(guc_to_i915(guc), -ENXIO);
- if (err)
- return err;
-
GEM_BUG_ON(ct->vma);
blob_size = 2 * CTB_DESC_SIZE + CTB_H2G_BUFFER_SIZE + CTB_G2H_BUFFER_SIZE;
@@ -306,6 +302,7 @@ int intel_guc_ct_init(struct intel_guc_ct *ct)
return 0;
}
+ALLOW_ERROR_INJECTION(intel_guc_ct_init, ERRNO);
/**
* intel_guc_ct_fini - Fini buffer-based communication
@@ -1394,9 +1391,6 @@ static void ct_dead_ct_worker_func(struct work_struct *w)
if (ct->dead_ct_reported)
return;
- if (i915_error_injected())
- return;
-
ct->dead_ct_reported = true;
guc_info(guc, "CTB is dead - reason=0x%X\n", ct->dead_ct_reason);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c
index 456d3372eef8..f3249b98c992 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c
@@ -541,10 +541,6 @@ int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type typ
if (intel_huc_is_authenticated(huc, type))
return -EEXIST;
- ret = i915_inject_probe_error(gt->i915, -ENXIO);
- if (ret)
- goto fail;
-
switch (type) {
case INTEL_HUC_AUTH_BY_GUC:
ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data));
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
index 4a3493e8d433..bd07c72a66fc 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
@@ -60,10 +60,6 @@ static int __intel_uc_reset_hw(struct intel_uc *uc)
int ret;
u32 guc_status;
- ret = i915_inject_probe_error(gt->i915, -ENXIO);
- if (ret)
- return ret;
-
ret = intel_reset_guc(gt);
if (ret) {
gt_err(gt, "Failed to reset GuC, ret = %d\n", ret);
@@ -220,15 +216,10 @@ static void guc_handle_mmio_msg(struct intel_guc *guc)
static int guc_enable_communication(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
- struct drm_i915_private *i915 = gt->i915;
int ret;
GEM_BUG_ON(intel_guc_ct_enabled(&guc->ct));
- ret = i915_inject_probe_error(i915, -ENXIO);
- if (ret)
- return ret;
-
ret = intel_guc_ct_enable(&guc->ct);
if (ret)
return ret;
@@ -323,9 +314,6 @@ static int __uc_init(struct intel_uc *uc)
if (!intel_uc_uses_guc(uc))
return 0;
- if (i915_inject_probe_failure(uc_to_gt(uc)->i915))
- return -ENOMEM;
-
ret = intel_guc_init(guc);
if (ret)
return ret;
@@ -338,6 +326,7 @@ static int __uc_init(struct intel_uc *uc)
return 0;
}
+ALLOW_ERROR_INJECTION(__uc_init, ERRNO);
static void __uc_fini(struct intel_uc *uc)
{
@@ -381,10 +370,6 @@ static int uc_init_wopcm(struct intel_uc *uc)
GEM_BUG_ON(!(size & GUC_WOPCM_SIZE_MASK));
GEM_BUG_ON(size & ~GUC_WOPCM_SIZE_MASK);
- err = i915_inject_probe_error(gt->i915, -ENXIO);
- if (err)
- return err;
-
mask = GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED;
err = intel_uncore_write_and_verify(uncore, GUC_WOPCM_SIZE, size, mask,
size | GUC_WOPCM_SIZE_LOCKED);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index e848a04a80dc..fd04fe892c28 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -542,43 +542,6 @@ void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
INTEL_UC_FIRMWARE_NOT_SUPPORTED);
}
-static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
-{
- struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
- bool user = e == -EINVAL;
-
- if (i915_inject_probe_error(i915, e)) {
- /* non-existing blob */
- uc_fw->file_selected.path = "<invalid>";
- uc_fw->user_overridden = user;
- } else if (i915_inject_probe_error(i915, e)) {
- /* require next major version */
- uc_fw->file_wanted.ver.major += 1;
- uc_fw->file_wanted.ver.minor = 0;
- uc_fw->user_overridden = user;
- } else if (i915_inject_probe_error(i915, e)) {
- /* require next minor version */
- uc_fw->file_wanted.ver.minor += 1;
- uc_fw->user_overridden = user;
- } else if (uc_fw->file_wanted.ver.major &&
- i915_inject_probe_error(i915, e)) {
- /* require prev major version */
- uc_fw->file_wanted.ver.major -= 1;
- uc_fw->file_wanted.ver.minor = 0;
- uc_fw->user_overridden = user;
- } else if (uc_fw->file_wanted.ver.minor &&
- i915_inject_probe_error(i915, e)) {
- /* require prev minor version - hey, this should work! */
- uc_fw->file_wanted.ver.minor -= 1;
- uc_fw->user_overridden = user;
- } else if (user && i915_inject_probe_error(i915, e)) {
- /* officially unsupported platform */
- uc_fw->file_wanted.ver.major = 0;
- uc_fw->file_wanted.ver.minor = 0;
- uc_fw->user_overridden = true;
- }
-}
-
static void uc_unpack_css_version(struct intel_uc_fw_ver *ver, u32 css_value)
{
/* Get version numbers from the CSS header */
@@ -766,7 +729,7 @@ static int guc_check_version_range(struct intel_uc_fw *uc_fw)
return -EINVAL;
}
- return i915_inject_probe_error(gt->i915, -EINVAL);
+ return 0;
}
static int check_fw_header(struct intel_gt *gt,
@@ -905,13 +868,6 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
GEM_BUG_ON(!gt->wopcm.size);
GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw));
- err = i915_inject_probe_error(i915, -ENXIO);
- if (err)
- goto fail;
-
- __force_fw_fetch_failures(uc_fw, -EINVAL);
- __force_fw_fetch_failures(uc_fw, -ESTALE);
-
err = try_firmware_load(uc_fw, &fw);
memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
@@ -1088,10 +1044,6 @@ static int uc_fw_xfer(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
u64 offset;
int ret;
- ret = i915_inject_probe_error(gt->i915, -ETIMEDOUT);
- if (ret)
- return ret;
-
intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
/* Set the source address for the uCode */
@@ -1155,16 +1107,11 @@ int intel_uc_fw_mark_load_failed(struct intel_uc_fw *uc_fw, int err)
*/
int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
{
- struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
int err;
/* make sure the status was cleared the last time we reset the uc */
GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
- err = i915_inject_probe_error(gt->i915, -ENOEXEC);
- if (err)
- return err;
-
if (!intel_uc_fw_is_loadable(uc_fw))
return -ENOEXEC;
@@ -1198,10 +1145,6 @@ static int uc_fw_rsa_data_create(struct intel_uc_fw *uc_fw)
void *vaddr;
int err;
- err = i915_inject_probe_error(gt->i915, -ENXIO);
- if (err)
- return err;
-
if (!uc_fw_need_rsa_in_memory(uc_fw))
return 0;
@@ -1243,6 +1186,7 @@ unpin_out:
i915_vma_unpin_and_release(&vma, 0);
return err;
}
+ALLOW_ERROR_INJECTION(uc_fw_rsa_data_create, ERRNO);
static void uc_fw_rsa_data_destroy(struct intel_uc_fw *uc_fw)
{
diff --git a/drivers/gpu/drm/i915/i915_display_pc8.c b/drivers/gpu/drm/i915/i915_display_pc8.c
new file mode 100644
index 000000000000..2af5dbab20ef
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_display_pc8.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2025, Intel Corporation.
+ */
+
+#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
+
+#include "i915_display_pc8.h"
+#include "i915_drv.h"
+#include "intel_uncore.h"
+
+static void i915_display_pc8_block(struct drm_device *drm)
+{
+ struct intel_uncore *uncore = &to_i915(drm)->uncore;
+
+ /* to prevent PC8 state, just enable force_wake */
+ intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
+}
+
+static void i915_display_pc8_unblock(struct drm_device *drm)
+{
+ struct intel_uncore *uncore = &to_i915(drm)->uncore;
+
+ intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
+}
+
+const struct intel_display_pc8_interface i915_display_pc8_interface = {
+ .block = i915_display_pc8_block,
+ .unblock = i915_display_pc8_unblock,
+};
diff --git a/drivers/gpu/drm/i915/i915_display_pc8.h b/drivers/gpu/drm/i915/i915_display_pc8.h
new file mode 100644
index 000000000000..717f313d2a21
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_display_pc8.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_DISPLAY_PC8_H__
+#define __I915_DISPLAY_PC8_H__
+
+extern const struct intel_display_pc8_interface i915_display_pc8_interface;
+
+#endif /* __I915_DISPLAY_PC8_H__ */
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index c97b76771917..e025273e9ab1 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -59,6 +59,7 @@
#include "display/intel_dmc.h"
#include "display/intel_dp.h"
#include "display/intel_dpt.h"
+#include "display/intel_dram.h"
#include "display/intel_encoder.h"
#include "display/intel_fbdev.h"
#include "display/intel_gmbus.h"
@@ -81,25 +82,28 @@
#include "gt/intel_gt_pm.h"
#include "gt/intel_gt_print.h"
#include "gt/intel_rc6.h"
+#include "gt/intel_rps.h"
#include "pxp/intel_pxp.h"
#include "pxp/intel_pxp_debugfs.h"
#include "pxp/intel_pxp_pm.h"
-#include "soc/intel_dram.h"
-#include "soc/intel_gmch.h"
-
#include "i915_debugfs.h"
+#include "i915_display_pc8.h"
#include "i915_driver.h"
#include "i915_drm_client.h"
#include "i915_drv.h"
+#include "i915_edram.h"
#include "i915_file_private.h"
#include "i915_getparam.h"
+#include "i915_gmch.h"
+#include "i915_hdcp_gsc.h"
#include "i915_hwmon.h"
#include "i915_ioc32.h"
#include "i915_ioctl.h"
#include "i915_irq.h"
#include "i915_memcpy.h"
+#include "i915_panic.h"
#include "i915_perf.h"
#include "i915_query.h"
#include "i915_reg.h"
@@ -224,9 +228,6 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
struct intel_display *display = dev_priv->display;
int ret = 0;
- if (i915_inject_probe_failure(dev_priv))
- return -ENODEV;
-
intel_device_info_runtime_init_early(dev_priv);
intel_step_init(dev_priv);
@@ -262,7 +263,7 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
intel_irq_init(dev_priv);
intel_display_driver_early_probe(display);
- intel_clock_gating_hooks_init(dev_priv);
+ intel_clock_gating_hooks_init(&dev_priv->drm);
intel_detect_preproduction_hw(dev_priv);
@@ -276,6 +277,7 @@ err_workqueues:
i915_workqueues_cleanup(dev_priv);
return ret;
}
+ALLOW_ERROR_INJECTION(i915_driver_early_probe, ERRNO);
/**
* i915_driver_late_release - cleanup the setup done in
@@ -318,10 +320,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
struct intel_gt *gt;
int ret, i;
- if (i915_inject_probe_failure(dev_priv))
- return -ENODEV;
-
- ret = intel_gmch_bridge_setup(dev_priv);
+ ret = i915_gmch_bridge_setup(dev_priv);
if (ret < 0)
return ret;
@@ -338,7 +337,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
}
/* Try to make sure MCHBAR is enabled before poking at it */
- intel_gmch_bar_setup(dev_priv);
+ i915_gmch_bar_setup(dev_priv);
intel_device_info_runtime_init(dev_priv);
intel_display_device_info_runtime_init(display);
@@ -354,10 +353,11 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
return 0;
err_uncore:
- intel_gmch_bar_teardown(dev_priv);
+ i915_gmch_bar_teardown(dev_priv);
return ret;
}
+ALLOW_ERROR_INJECTION(i915_driver_mmio_probe, ERRNO);
/**
* i915_driver_mmio_release - cleanup the setup done in i915_driver_mmio_probe()
@@ -365,7 +365,7 @@ err_uncore:
*/
static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
{
- intel_gmch_bar_teardown(dev_priv);
+ i915_gmch_bar_teardown(dev_priv);
}
/**
@@ -465,9 +465,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
int ret;
- if (i915_inject_probe_failure(dev_priv))
- return -ENODEV;
-
if (HAS_PPGTT(dev_priv)) {
if (intel_vgpu_active(dev_priv) &&
!intel_vgpu_has_full_ppgtt(dev_priv)) {
@@ -492,7 +489,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
}
/* needs to be done before ggtt probe */
- intel_dram_edram_detect(dev_priv);
+ i915_edram_detect(dev_priv);
ret = i915_set_dma_info(dev_priv);
if (ret)
@@ -572,7 +569,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
* Fill the dram structure to get the system dram info. This will be
* used for memory latency calculation.
*/
- ret = intel_dram_detect(dev_priv);
+ ret = intel_dram_detect(display);
if (ret)
goto err_opregion;
@@ -595,6 +592,7 @@ err_perf:
i915_perf_fini(dev_priv);
return ret;
}
+ALLOW_ERROR_INJECTION(i915_driver_hw_probe, ERRNO);
/**
* i915_driver_hw_remove - cleanup the setup done in i915_driver_hw_probe()
@@ -739,8 +737,44 @@ static void i915_welcome_messages(struct drm_i915_private *dev_priv)
"DRM_I915_DEBUG_RUNTIME_PM enabled\n");
}
+static void fence_priority_display(struct dma_fence *fence)
+{
+ if (dma_fence_is_i915(fence))
+ i915_gem_fence_wait_priority_display(fence);
+}
+
+static bool has_auxccs(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+
+ return IS_GRAPHICS_VER(i915, 9, 12) ||
+ IS_ALDERLAKE_P(i915) ||
+ IS_METEORLAKE(i915);
+}
+
+static bool has_fenced_regions(struct drm_device *drm)
+{
+ return intel_gt_support_legacy_fencing(to_gt(to_i915(drm)));
+}
+
+static bool vgpu_active(struct drm_device *drm)
+{
+ return intel_vgpu_active(to_i915(drm));
+}
+
static const struct intel_display_parent_interface parent = {
+ .hdcp = &i915_display_hdcp_interface,
+ .irq = &i915_display_irq_interface,
+ .panic = &i915_display_panic_interface,
+ .pc8 = &i915_display_pc8_interface,
.rpm = &i915_display_rpm_interface,
+ .rps = &i915_display_rps_interface,
+ .stolen = &i915_display_stolen_interface,
+
+ .fence_priority_display = fence_priority_display,
+ .has_auxccs = has_auxccs,
+ .has_fenced_regions = has_fenced_regions,
+ .vgpu_active = vgpu_active,
};
const struct intel_display_parent_interface *i915_driver_parent_interface(void)
@@ -890,6 +924,7 @@ out_cleanup_hw:
i915_gem_drain_freed_objects(i915);
i915_ggtt_driver_late_release(i915);
out_cleanup_mmio:
+ intel_gvt_driver_remove(i915);
i915_driver_mmio_release(i915);
out_runtime_pm_put:
enable_rpm_wakeref_asserts(&i915->runtime_pm);
@@ -1254,7 +1289,7 @@ static int i915_drm_resume(struct drm_device *dev)
intel_display_driver_init_hw(display);
- intel_clock_gating_init(dev_priv);
+ intel_clock_gating_init(&dev_priv->drm);
if (intel_display_device_present(display))
intel_display_driver_resume_access(display);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5381a934a671..44ba620325bc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -60,7 +60,6 @@
#include "intel_step.h"
#include "intel_uncore.h"
-struct dram_info;
struct drm_i915_clock_gating_funcs;
struct intel_display;
struct intel_pxp;
@@ -141,11 +140,6 @@ struct i915_gem_mm {
*/
atomic_t free_count;
- /**
- * tmpfs instance used for shmem backed objects
- */
- struct vfsmount *gemfs;
-
struct intel_memory_region *regions[INTEL_REGION_UNKNOWN];
struct notifier_block oom_notifier;
@@ -279,8 +273,6 @@ struct drm_i915_private {
u32 suspend_count;
struct vlv_s0ix_state *vlv_s0ix_state;
- const struct dram_info *dram_info;
-
struct intel_runtime_pm runtime_pm;
struct i915_perf perf;
diff --git a/drivers/gpu/drm/i915/i915_edram.c b/drivers/gpu/drm/i915/i915_edram.c
new file mode 100644
index 000000000000..5818ec396d1e
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_edram.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: MIT
+/* Copyright © 2025 Intel Corporation */
+
+#include <drm/drm_print.h>
+
+#include "i915_drv.h"
+#include "i915_edram.h"
+#include "i915_reg.h"
+
+static u32 gen9_edram_size_mb(struct drm_i915_private *i915, u32 cap)
+{
+ static const u8 ways[8] = { 4, 8, 12, 16, 16, 16, 16, 16 };
+ static const u8 sets[4] = { 1, 1, 2, 2 };
+
+ return EDRAM_NUM_BANKS(cap) *
+ ways[EDRAM_WAYS_IDX(cap)] *
+ sets[EDRAM_SETS_IDX(cap)];
+}
+
+void i915_edram_detect(struct drm_i915_private *i915)
+{
+ u32 edram_cap = 0;
+
+ if (!(IS_HASWELL(i915) || IS_BROADWELL(i915) || GRAPHICS_VER(i915) >= 9))
+ return;
+
+ edram_cap = intel_uncore_read_fw(&i915->uncore, HSW_EDRAM_CAP);
+
+ /* NB: We can't write IDICR yet because we don't have gt funcs set up */
+
+ if (!(edram_cap & EDRAM_ENABLED))
+ return;
+
+ /*
+ * The needed capability bits for size calculation are not there with
+ * pre gen9 so return 128MB always.
+ */
+ if (GRAPHICS_VER(i915) < 9)
+ i915->edram_size_mb = 128;
+ else
+ i915->edram_size_mb = gen9_edram_size_mb(i915, edram_cap);
+
+ drm_info(&i915->drm, "Found %uMB of eDRAM\n", i915->edram_size_mb);
+}
diff --git a/drivers/gpu/drm/i915/i915_edram.h b/drivers/gpu/drm/i915/i915_edram.h
new file mode 100644
index 000000000000..8319422ace9d
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_edram.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_DRAM_H__
+#define __I915_DRAM_H__
+
+struct drm_i915_private;
+
+void i915_edram_detect(struct drm_i915_private *i915);
+
+#endif /* __I915_DRAM_H__ */
diff --git a/drivers/gpu/drm/i915/i915_freq.c b/drivers/gpu/drm/i915/i915_freq.c
new file mode 100644
index 000000000000..9bdaea34aef9
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_freq.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: MIT
+/* Copyright © 2025 Intel Corporation */
+
+#include <drm/drm_print.h>
+
+#include "i915_drv.h"
+#include "i915_freq.h"
+#include "intel_mchbar_regs.h"
+
+unsigned int i9xx_fsb_freq(struct drm_i915_private *i915)
+{
+ u32 fsb;
+
+ /*
+ * Note that this only reads the state of the FSB
+ * straps, not the actual FSB frequency. Some BIOSen
+ * let you configure each independently. Ideally we'd
+ * read out the actual FSB frequency but sadly we
+ * don't know which registers have that information,
+ * and all the relevant docs have gone to bit heaven :(
+ */
+ fsb = intel_uncore_read(&i915->uncore, CLKCFG) & CLKCFG_FSB_MASK;
+
+ if (IS_PINEVIEW(i915) || IS_MOBILE(i915)) {
+ switch (fsb) {
+ case CLKCFG_FSB_400:
+ return 400000;
+ case CLKCFG_FSB_533:
+ return 533333;
+ case CLKCFG_FSB_667:
+ return 666667;
+ case CLKCFG_FSB_800:
+ return 800000;
+ case CLKCFG_FSB_1067:
+ return 1066667;
+ case CLKCFG_FSB_1333:
+ return 1333333;
+ default:
+ MISSING_CASE(fsb);
+ return 1333333;
+ }
+ } else {
+ switch (fsb) {
+ case CLKCFG_FSB_400_ALT:
+ return 400000;
+ case CLKCFG_FSB_533:
+ return 533333;
+ case CLKCFG_FSB_667:
+ return 666667;
+ case CLKCFG_FSB_800:
+ return 800000;
+ case CLKCFG_FSB_1067_ALT:
+ return 1066667;
+ case CLKCFG_FSB_1333_ALT:
+ return 1333333;
+ case CLKCFG_FSB_1600_ALT:
+ return 1600000;
+ default:
+ MISSING_CASE(fsb);
+ return 1333333;
+ }
+ }
+}
+
+unsigned int ilk_fsb_freq(struct drm_i915_private *i915)
+{
+ u16 fsb;
+
+ fsb = intel_uncore_read16(&i915->uncore, CSIPLL0) & 0x3ff;
+
+ switch (fsb) {
+ case 0x00c:
+ return 3200000;
+ case 0x00e:
+ return 3733333;
+ case 0x010:
+ return 4266667;
+ case 0x012:
+ return 4800000;
+ case 0x014:
+ return 5333333;
+ case 0x016:
+ return 5866667;
+ case 0x018:
+ return 6400000;
+ default:
+ drm_dbg(&i915->drm, "unknown fsb frequency 0x%04x\n", fsb);
+ return 0;
+ }
+}
+
+unsigned int ilk_mem_freq(struct drm_i915_private *i915)
+{
+ u16 ddrpll;
+
+ ddrpll = intel_uncore_read16(&i915->uncore, DDRMPLL1);
+ switch (ddrpll & 0xff) {
+ case 0xc:
+ return 800000;
+ case 0x10:
+ return 1066667;
+ case 0x14:
+ return 1333333;
+ case 0x18:
+ return 1600000;
+ default:
+ drm_dbg(&i915->drm, "unknown memory frequency 0x%02x\n",
+ ddrpll & 0xff);
+ return 0;
+ }
+}
diff --git a/drivers/gpu/drm/i915/i915_freq.h b/drivers/gpu/drm/i915/i915_freq.h
new file mode 100644
index 000000000000..53b0ecb95440
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_freq.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_FREQ_H__
+#define __I915_FREQ_H__
+
+struct drm_i915_private;
+
+unsigned int i9xx_fsb_freq(struct drm_i915_private *i915);
+unsigned int ilk_fsb_freq(struct drm_i915_private *i915);
+unsigned int ilk_mem_freq(struct drm_i915_private *i915);
+
+#endif /* __I915_FREQ_H__ */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4c82c9544b93..b40d4d88de01 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1184,7 +1184,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
*
* FIXME: break up the workarounds and apply them at the right time!
*/
- intel_clock_gating_init(dev_priv);
+ intel_clock_gating_init(&dev_priv->drm);
for_each_gt(gt, dev_priv, i) {
ret = intel_gt_init(gt);
@@ -1235,7 +1235,7 @@ err_unlock:
/* Minimal basic recovery for KMS */
ret = i915_ggtt_enable_hw(dev_priv);
i915_ggtt_resume(to_gt(dev_priv)->ggtt);
- intel_clock_gating_init(dev_priv);
+ intel_clock_gating_init(&dev_priv->drm);
}
i915_gem_drain_freed_objects(dev_priv);
diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/i915_gmch.c
index 271da30c8290..2d55831b3c58 100644
--- a/drivers/gpu/drm/i915/soc/intel_gmch.c
+++ b/drivers/gpu/drm/i915/i915_gmch.c
@@ -1,28 +1,21 @@
// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2023 Intel Corporation
- */
+/* Copyright © 2025 Intel Corporation */
-#include <linux/pci.h>
#include <linux/pnp.h>
-#include <linux/vgaarb.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
-#include <drm/intel/i915_drm.h>
-
-#include "../display/intel_display_core.h" /* FIXME */
#include "i915_drv.h"
-#include "intel_gmch.h"
+#include "i915_gmch.h"
#include "intel_pci_config.h"
-static void intel_gmch_bridge_release(struct drm_device *dev, void *bridge)
+static void i915_gmch_bridge_release(struct drm_device *dev, void *bridge)
{
pci_dev_put(bridge);
}
-int intel_gmch_bridge_setup(struct drm_i915_private *i915)
+int i915_gmch_bridge_setup(struct drm_i915_private *i915)
{
int domain = pci_domain_nr(to_pci_dev(i915->drm.dev)->bus);
@@ -32,7 +25,7 @@ int intel_gmch_bridge_setup(struct drm_i915_private *i915)
return -EIO;
}
- return drmm_add_action_or_reset(&i915->drm, intel_gmch_bridge_release,
+ return drmm_add_action_or_reset(&i915->drm, i915_gmch_bridge_release,
i915->gmch.pdev);
}
@@ -84,7 +77,7 @@ intel_alloc_mchbar_resource(struct drm_i915_private *i915)
}
/* Setup MCHBAR if possible, return true if we should disable it again */
-void intel_gmch_bar_setup(struct drm_i915_private *i915)
+void i915_gmch_bar_setup(struct drm_i915_private *i915)
{
u32 temp;
bool enabled;
@@ -121,7 +114,7 @@ void intel_gmch_bar_setup(struct drm_i915_private *i915)
}
}
-void intel_gmch_bar_teardown(struct drm_i915_private *i915)
+void i915_gmch_bar_teardown(struct drm_i915_private *i915)
{
if (i915->gmch.mchbar_need_disable) {
if (IS_I915G(i915) || IS_I915GM(i915)) {
@@ -146,43 +139,3 @@ void intel_gmch_bar_teardown(struct drm_i915_private *i915)
if (i915->gmch.mch_res.start)
release_resource(&i915->gmch.mch_res);
}
-
-int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
-{
- struct intel_display *display = i915->display;
- unsigned int reg = DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
- u16 gmch_ctrl;
-
- if (pci_read_config_word(i915->gmch.pdev, reg, &gmch_ctrl)) {
- drm_err(&i915->drm, "failed to read control word\n");
- return -EIO;
- }
-
- if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
- return 0;
-
- if (enable_decode)
- gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
- else
- gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
-
- if (pci_write_config_word(i915->gmch.pdev, reg, gmch_ctrl)) {
- drm_err(&i915->drm, "failed to write control word\n");
- return -EIO;
- }
-
- return 0;
-}
-
-unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
-{
- struct drm_i915_private *i915 = pdev_to_i915(pdev);
-
- intel_gmch_vga_set_state(i915, enable_decode);
-
- if (enable_decode)
- return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
- VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
- else
- return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
-}
diff --git a/drivers/gpu/drm/i915/i915_gmch.h b/drivers/gpu/drm/i915/i915_gmch.h
new file mode 100644
index 000000000000..3ae50bef04ea
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gmch.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_GMCH_H__
+#define __I915_GMCH_H__
+
+struct drm_i915_private;
+
+int i915_gmch_bridge_setup(struct drm_i915_private *i915);
+void i915_gmch_bar_setup(struct drm_i915_private *i915);
+void i915_gmch_bar_teardown(struct drm_i915_private *i915);
+
+#endif /* __I915_GMCH_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/i915_hdcp_gsc.c
index 3e7b480ee9f1..9906da2aef1c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c
+++ b/drivers/gpu/drm/i915/i915_hdcp_gsc.c
@@ -4,13 +4,14 @@
*/
#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
#include <drm/intel/i915_hdcp_interface.h>
#include "gem/i915_gem_region.h"
#include "gt/intel_gt.h"
#include "gt/uc/intel_gsc_uc_heci_cmd_submit.h"
#include "i915_drv.h"
-#include "intel_hdcp_gsc.h"
+#include "i915_hdcp_gsc.h"
struct intel_hdcp_gsc_context {
struct drm_i915_private *i915;
@@ -19,7 +20,7 @@ struct intel_hdcp_gsc_context {
void *hdcp_cmd_out;
};
-bool intel_hdcp_gsc_check_status(struct drm_device *drm)
+static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
struct intel_gt *gt = i915->media_gt;
@@ -87,7 +88,7 @@ out_unpin:
return err;
}
-struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
+static struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
struct intel_hdcp_gsc_context *gsc_context;
@@ -111,7 +112,7 @@ struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *d
return gsc_context;
}
-void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
+static void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
{
if (!gsc_context)
return;
@@ -168,9 +169,9 @@ static int intel_gsc_send_sync(struct drm_i915_private *i915,
* gsc cs memory header as stated in specs after which the normal HDCP payload
* will follow
*/
-ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
- void *msg_in, size_t msg_in_len,
- void *msg_out, size_t msg_out_len)
+static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len)
{
struct drm_i915_private *i915 = gsc_context->i915;
struct intel_gt *gt = i915->media_gt;
@@ -237,3 +238,10 @@ ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
err:
return ret;
}
+
+const struct intel_display_hdcp_interface i915_display_hdcp_interface = {
+ .gsc_msg_send = intel_hdcp_gsc_msg_send,
+ .gsc_check_status = intel_hdcp_gsc_check_status,
+ .gsc_context_alloc = intel_hdcp_gsc_context_alloc,
+ .gsc_context_free = intel_hdcp_gsc_context_free,
+};
diff --git a/drivers/gpu/drm/i915/i915_hdcp_gsc.h b/drivers/gpu/drm/i915/i915_hdcp_gsc.h
new file mode 100644
index 000000000000..e0b562cfcde3
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_hdcp_gsc.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_HDCP_GSC_H__
+#define __I915_HDCP_GSC_H__
+
+extern const struct intel_display_hdcp_interface i915_display_hdcp_interface;
+
+#endif /* __I915_HDCP_GSC_H__ */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1898be4ddc8b..3fe978d4ea53 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -33,6 +33,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
#include "display/intel_display_irq.h"
#include "display/intel_hotplug.h"
@@ -1252,3 +1253,18 @@ void intel_synchronize_hardirq(struct drm_i915_private *i915)
{
synchronize_hardirq(to_pci_dev(i915->drm.dev)->irq);
}
+
+static bool _intel_irq_enabled(struct drm_device *drm)
+{
+ return intel_irqs_enabled(to_i915(drm));
+}
+
+static void _intel_irq_synchronize(struct drm_device *drm)
+{
+ return intel_synchronize_irq(to_i915(drm));
+}
+
+const struct intel_display_irq_interface i915_display_irq_interface = {
+ .enabled = _intel_irq_enabled,
+ .synchronize = _intel_irq_synchronize,
+};
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index 58789b264575..5c87d6d41c74 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -51,4 +51,6 @@ void gen2_error_reset(struct intel_uncore *uncore, struct i915_error_regs regs);
void gen2_error_init(struct intel_uncore *uncore, struct i915_error_regs regs,
u32 emr_val);
+extern const struct intel_display_irq_interface i915_display_irq_interface;
+
#endif /* __I915_IRQ_H__ */
diff --git a/drivers/gpu/drm/i915/i915_panic.c b/drivers/gpu/drm/i915/i915_panic.c
new file mode 100644
index 000000000000..728be077e8e8
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_panic.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT
+/* Copyright © 2025 Intel Corporation */
+
+#include <drm/drm_panic.h>
+#include <drm/intel/display_parent_interface.h>
+
+#include "display/intel_display_types.h"
+#include "display/intel_fb.h"
+#include "gem/i915_gem_object.h"
+
+#include "i915_panic.h"
+
+static struct intel_panic *intel_panic_alloc(void)
+{
+ return i915_gem_object_alloc_panic();
+}
+
+static int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
+{
+ struct intel_framebuffer *fb = sb->private;
+ struct drm_gem_object *obj = intel_fb_bo(&fb->base);
+
+ return i915_gem_object_panic_setup(panic, sb, obj, fb->panic_tiling);
+}
+
+static void intel_panic_finish(struct intel_panic *panic)
+{
+ return i915_gem_object_panic_finish(panic);
+}
+
+const struct intel_display_panic_interface i915_display_panic_interface = {
+ .alloc = intel_panic_alloc,
+ .setup = intel_panic_setup,
+ .finish = intel_panic_finish,
+};
diff --git a/drivers/gpu/drm/i915/i915_panic.h b/drivers/gpu/drm/i915/i915_panic.h
new file mode 100644
index 000000000000..743d8c861c42
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_panic.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __I915_PANIC_H__
+#define __I915_PANIC_H__
+
+extern const struct intel_display_panic_interface i915_display_panic_interface;
+
+#endif /* __I915_PANIC_H__ */
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 37746dd619fd..34ed82bb1b1a 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -110,11 +110,6 @@ i915_param_named_unsafe(huc_firmware_path, charp, 0400,
i915_param_named_unsafe(gsc_firmware_path, charp, 0400,
"GSC firmware path to use instead of the default one");
-#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
-i915_param_named_unsafe(inject_probe_failure, uint, 0400,
- "Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)");
-#endif
-
#if IS_ENABLED(CONFIG_DRM_I915_GVT)
i915_param_named(enable_gvt, bool, 0400,
"Enable support for Intel GVT-g graphics virtualization host support(default:false)");
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 0fbcb5b6d7bf..4d9d4cd3220d 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -55,7 +55,6 @@ struct drm_printer;
param(bool, memtest, false, 0400) \
param(int, mmio_debug, -IS_ENABLED(CONFIG_DRM_I915_DEBUG_MMIO), 0600) \
param(unsigned int, reset, 3, 0600) \
- param(unsigned int, inject_probe_failure, 0, 0) \
param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE, 0400) \
param(unsigned int, request_timeout_ms, CONFIG_DRM_I915_REQUEST_TIMEOUT, CONFIG_DRM_I915_REQUEST_TIMEOUT ? 0600 : 0) \
param(unsigned int, lmem_size, 0, 0400) \
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index b2e311f4791a..d966a00520f1 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -999,11 +999,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
return err;
- if (i915_inject_probe_failure(pdev_to_i915(pdev))) {
- i915_pci_remove(pdev);
- return -ENODEV;
- }
-
err = i915_live_selftests(pdev);
if (err) {
i915_pci_remove(pdev);
@@ -1018,6 +1013,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
}
+ALLOW_ERROR_INJECTION(i915_pci_probe, ERRNO);
static void i915_pci_shutdown(struct pci_dev *pdev)
{
diff --git a/drivers/gpu/drm/i915/i915_utils.c b/drivers/gpu/drm/i915/i915_utils.c
index 89b920ccbccb..8c1aad312fd4 100644
--- a/drivers/gpu/drm/i915/i915_utils.c
+++ b/drivers/gpu/drm/i915/i915_utils.c
@@ -17,37 +17,9 @@ void add_taint_for_CI(struct drm_i915_private *i915, unsigned int taint)
drm_notice(&i915->drm, "CI tainted: %#x by %pS\n",
taint, __builtin_return_address(0));
- /* Failures that occur during fault injection testing are expected */
- if (!i915_error_injected())
- __add_taint_for_CI(taint);
+ __add_taint_for_CI(taint);
}
-#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
-static unsigned int i915_probe_fail_count;
-
-int __i915_inject_probe_error(struct drm_i915_private *i915, int err,
- const char *func, int line)
-{
- if (i915_probe_fail_count >= i915_modparams.inject_probe_failure)
- return 0;
-
- if (++i915_probe_fail_count < i915_modparams.inject_probe_failure)
- return 0;
-
- drm_info(&i915->drm, "Injecting failure %d at checkpoint %u [%s:%d]\n",
- err, i915_modparams.inject_probe_failure, func, line);
-
- i915_modparams.inject_probe_failure = 0;
- return err;
-}
-
-bool i915_error_injected(void)
-{
- return i915_probe_fail_count && !i915_modparams.inject_probe_failure;
-}
-
-#endif
-
bool i915_vtd_active(struct drm_i915_private *i915)
{
if (device_iommu_mapped(i915->drm.dev))
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index 4f75115b87d6..9e5b7fcadbe2 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -43,28 +43,8 @@ struct drm_i915_private;
__stringify(x), (long)(x))
#endif
-#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
-
-int __i915_inject_probe_error(struct drm_i915_private *i915, int err,
- const char *func, int line);
-#define i915_inject_probe_error(_i915, _err) \
- __i915_inject_probe_error((_i915), (_err), __func__, __LINE__)
-bool i915_error_injected(void);
-
-#else
-
-#define i915_inject_probe_error(i915, e) ({ BUILD_BUG_ON_INVALID(i915); 0; })
-#define i915_error_injected() false
-
-#endif
-
-#define i915_inject_probe_failure(i915) i915_inject_probe_error((i915), -ENODEV)
-
#define i915_probe_error(i915, fmt, ...) ({ \
- if (i915_error_injected()) \
- drm_dbg(&(i915)->drm, fmt, ##__VA_ARGS__); \
- else \
- drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \
+ drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \
})
#ifndef fetch_and_zero
diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c
index 175a240ac848..7336934bb934 100644
--- a/drivers/gpu/drm/i915/intel_clock_gating.c
+++ b/drivers/gpu/drm/i915/intel_clock_gating.c
@@ -709,8 +709,10 @@ static void i830_init_clock_gating(struct drm_i915_private *i915)
_MASKED_BIT_ENABLE(MEM_DISPLAY_B_TRICKLE_FEED_DISABLE));
}
-void intel_clock_gating_init(struct drm_i915_private *i915)
+void intel_clock_gating_init(struct drm_device *drm)
{
+ struct drm_i915_private *i915 = to_i915(drm);
+
i915->clock_gating_funcs->init_clock_gating(i915);
}
@@ -749,15 +751,17 @@ CG_FUNCS(nop);
/**
* intel_clock_gating_hooks_init - setup the clock gating hooks
- * @i915: device private
+ * @drm: drm device
*
* Setup the hooks that configure which clocks of a given platform can be
* gated and also apply various GT and display specific workarounds for these
* platforms. Note that some GT specific workarounds are applied separately
* when GPU contexts or batchbuffers start their execution.
*/
-void intel_clock_gating_hooks_init(struct drm_i915_private *i915)
+void intel_clock_gating_hooks_init(struct drm_device *drm)
{
+ struct drm_i915_private *i915 = to_i915(drm);
+
if (IS_DG2(i915))
i915->clock_gating_funcs = &dg2_clock_gating_funcs;
else if (IS_COFFEELAKE(i915) || IS_COMETLAKE(i915))
diff --git a/drivers/gpu/drm/i915/intel_clock_gating.h b/drivers/gpu/drm/i915/intel_clock_gating.h
index 5b4e4c55b2c2..3a4b443d9b8b 100644
--- a/drivers/gpu/drm/i915/intel_clock_gating.h
+++ b/drivers/gpu/drm/i915/intel_clock_gating.h
@@ -6,9 +6,9 @@
#ifndef __INTEL_CLOCK_GATING_H__
#define __INTEL_CLOCK_GATING_H__
-struct drm_i915_private;
+struct drm_device;
-void intel_clock_gating_init(struct drm_i915_private *i915);
-void intel_clock_gating_hooks_init(struct drm_i915_private *i915);
+void intel_clock_gating_init(struct drm_device *drm);
+void intel_clock_gating_hooks_init(struct drm_device *drm);
#endif /* __INTEL_CLOCK_GATING_H__ */
diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c
index c3efc3454ec2..5f615ec0e580 100644
--- a/drivers/gpu/drm/i915/intel_gvt.c
+++ b/drivers/gpu/drm/i915/intel_gvt.c
@@ -238,9 +238,6 @@ EXPORT_SYMBOL_NS_GPL(intel_gvt_clear_ops, "I915_GVT");
*/
int intel_gvt_init(struct drm_i915_private *dev_priv)
{
- if (i915_inject_probe_failure(dev_priv))
- return -ENODEV;
-
mutex_lock(&intel_gvt_mutex);
list_add_tail(&dev_priv->vgpu.entry, &intel_gvt_devices);
if (intel_gvt_ops)
diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h
index dc2477179c3e..614d4017b57b 100644
--- a/drivers/gpu/drm/i915/intel_mchbar_regs.h
+++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h
@@ -130,11 +130,11 @@
#define DG1_DRAM_T_RAS_MASK REG_GENMASK(8, 1)
#define SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5000)
-#define SKL_DRAM_DDR_TYPE_MASK (0x3 << 0)
-#define SKL_DRAM_DDR_TYPE_DDR4 (0 << 0)
-#define SKL_DRAM_DDR_TYPE_DDR3 (1 << 0)
-#define SKL_DRAM_DDR_TYPE_LPDDR3 (2 << 0)
-#define SKL_DRAM_DDR_TYPE_LPDDR4 (3 << 0)
+#define SKL_DRAM_DDR_TYPE_MASK REG_GENMASK(1, 0)
+#define SKL_DRAM_DDR_TYPE_DDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 0)
+#define SKL_DRAM_DDR_TYPE_DDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 1)
+#define SKL_DRAM_DDR_TYPE_LPDDR3 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 2)
+#define SKL_DRAM_DDR_TYPE_LPDDR4 REG_FIELD_PREP(SKL_DRAM_DDR_TYPE_MASK, 3)
/* snb MCH registers for reading the DRAM channel configuration */
#define MAD_DIMM_C0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004)
@@ -160,30 +160,40 @@
#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010)
-#define SKL_DRAM_S_SHIFT 16
-#define SKL_DRAM_SIZE_MASK 0x3F
-#define SKL_DRAM_WIDTH_MASK (0x3 << 8)
-#define SKL_DRAM_WIDTH_SHIFT 8
-#define SKL_DRAM_WIDTH_X8 (0x0 << 8)
-#define SKL_DRAM_WIDTH_X16 (0x1 << 8)
-#define SKL_DRAM_WIDTH_X32 (0x2 << 8)
-#define SKL_DRAM_RANK_MASK (0x1 << 10)
-#define SKL_DRAM_RANK_SHIFT 10
-#define SKL_DRAM_RANK_1 (0x0 << 10)
-#define SKL_DRAM_RANK_2 (0x1 << 10)
-#define SKL_DRAM_RANK_MASK (0x1 << 10)
-#define ICL_DRAM_SIZE_MASK 0x7F
-#define ICL_DRAM_WIDTH_MASK (0x3 << 7)
-#define ICL_DRAM_WIDTH_SHIFT 7
-#define ICL_DRAM_WIDTH_X8 (0x0 << 7)
-#define ICL_DRAM_WIDTH_X16 (0x1 << 7)
-#define ICL_DRAM_WIDTH_X32 (0x2 << 7)
-#define ICL_DRAM_RANK_MASK (0x3 << 9)
-#define ICL_DRAM_RANK_SHIFT 9
-#define ICL_DRAM_RANK_1 (0x0 << 9)
-#define ICL_DRAM_RANK_2 (0x1 << 9)
-#define ICL_DRAM_RANK_3 (0x2 << 9)
-#define ICL_DRAM_RANK_4 (0x3 << 9)
+#define SKL_DIMM_S_RANK_MASK REG_GENMASK(26, 26)
+#define SKL_DIMM_S_RANK_1 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 0)
+#define SKL_DIMM_S_RANK_2 REG_FIELD_PREP(SKL_DIMM_S_RANK_MASK, 1)
+#define SKL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24)
+#define SKL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 0)
+#define SKL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 1)
+#define SKL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_S_WIDTH_MASK, 2)
+#define SKL_DIMM_S_SIZE_MASK REG_GENMASK(21, 16)
+#define SKL_DIMM_L_RANK_MASK REG_GENMASK(10, 10)
+#define SKL_DIMM_L_RANK_1 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 0)
+#define SKL_DIMM_L_RANK_2 REG_FIELD_PREP(SKL_DIMM_L_RANK_MASK, 1)
+#define SKL_DIMM_L_WIDTH_MASK REG_GENMASK(9, 8)
+#define SKL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 0)
+#define SKL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 1)
+#define SKL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(SKL_DIMM_L_WIDTH_MASK, 2)
+#define SKL_DIMM_L_SIZE_MASK REG_GENMASK(5, 0)
+#define ICL_DIMM_S_RANK_MASK REG_GENMASK(27, 26)
+#define ICL_DIMM_S_RANK_1 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 0)
+#define ICL_DIMM_S_RANK_2 REG_FIELD_PREP(ICL_DIMM_S_RANK_MASK, 1)
+#define ICL_DIMM_S_WIDTH_MASK REG_GENMASK(25, 24)
+#define ICL_DIMM_S_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 0)
+#define ICL_DIMM_S_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 1)
+#define ICL_DIMM_S_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_S_WIDTH_MASK, 2)
+#define ICL_DIMM_S_SIZE_MASK REG_GENMASK(22, 16)
+#define ICL_DIMM_L_RANK_MASK REG_GENMASK(10, 9)
+#define ICL_DIMM_L_RANK_1 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 0)
+#define ICL_DIMM_L_RANK_2 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 1)
+#define ICL_DIMM_L_RANK_3 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 2)
+#define ICL_DIMM_L_RANK_4 REG_FIELD_PREP(ICL_DIMM_L_RANK_MASK, 3)
+#define ICL_DIMM_L_WIDTH_MASK REG_GENMASK(8, 7)
+#define ICL_DIMM_L_WIDTH_X8 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 0)
+#define ICL_DIMM_L_WIDTH_X16 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 1)
+#define ICL_DIMM_L_WIDTH_X32 REG_FIELD_PREP(ICL_DIMM_L_WIDTH_MASK, 2)
+#define ICL_DIMM_L_SIZE_MASK REG_GENMASK(6, 0)
#define SA_PERF_STATUS_0_0_0_MCHBAR_PC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5918)
#define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2)
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 4adeb271fcbf..fdd2a940f983 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -2072,9 +2072,6 @@ static int __fw_domain_init(struct intel_uncore *uncore,
GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
GEM_BUG_ON(uncore->fw_domain[domain_id]);
- if (i915_inject_probe_failure(uncore->i915))
- return -ENOMEM;
-
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
@@ -2118,6 +2115,7 @@ static int __fw_domain_init(struct intel_uncore *uncore,
return 0;
}
+ALLOW_ERROR_INJECTION(__fw_domain_init, ERRNO);
static void fw_domain_fini(struct intel_uncore *uncore,
enum forcewake_domain_id domain_id)
diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c
index b1883dccc22a..98e7cee4e1dc 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.c
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
@@ -80,7 +80,7 @@ void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags)
/* Assume we are not in process context and so cannot sleep. */
if (flags & INTEL_WAKEREF_PUT_ASYNC || !mutex_trylock(&wf->mutex)) {
mod_delayed_work(wf->i915->unordered_wq, &wf->work,
- FIELD_GET(INTEL_WAKEREF_PUT_DELAY, flags));
+ FIELD_GET(INTEL_WAKEREF_PUT_DELAY_MASK, flags));
return;
}
diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h
index a2894a56e18f..81308bac34ba 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.h
+++ b/drivers/gpu/drm/i915/intel_wakeref.h
@@ -128,17 +128,16 @@ intel_wakeref_get_if_active(struct intel_wakeref *wf)
return atomic_inc_not_zero(&wf->count);
}
-enum {
- INTEL_WAKEREF_PUT_ASYNC_BIT = 0,
- __INTEL_WAKEREF_PUT_LAST_BIT__
-};
-
static inline void
intel_wakeref_might_get(struct intel_wakeref *wf)
{
might_lock(&wf->mutex);
}
+/* flags for __intel_wakeref_put() and __intel_wakeref_put_last */
+#define INTEL_WAKEREF_PUT_ASYNC BIT(0)
+#define INTEL_WAKEREF_PUT_DELAY_MASK GENMASK(BITS_PER_LONG - 1, 1)
+
/**
* __intel_wakeref_put: Release the wakeref
* @wf: the wakeref
@@ -154,9 +153,6 @@ intel_wakeref_might_get(struct intel_wakeref *wf)
*/
static inline void
__intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags)
-#define INTEL_WAKEREF_PUT_ASYNC BIT(INTEL_WAKEREF_PUT_ASYNC_BIT)
-#define INTEL_WAKEREF_PUT_DELAY \
- GENMASK(BITS_PER_LONG - 1, __INTEL_WAKEREF_PUT_LAST_BIT__)
{
INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
if (unlikely(!atomic_add_unless(&wf->count, -1, 1)))
@@ -181,7 +177,7 @@ intel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay)
{
__intel_wakeref_put(wf,
INTEL_WAKEREF_PUT_ASYNC |
- FIELD_PREP(INTEL_WAKEREF_PUT_DELAY, delay));
+ FIELD_PREP(INTEL_WAKEREF_PUT_DELAY_MASK, delay));
}
static inline void
diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.h b/drivers/gpu/drm/i915/soc/intel_gmch.h
deleted file mode 100644
index 23be2d113afd..000000000000
--- a/drivers/gpu/drm/i915/soc/intel_gmch.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#ifndef __INTEL_GMCH_H__
-#define __INTEL_GMCH_H__
-
-#include <linux/types.h>
-
-struct pci_dev;
-struct drm_i915_private;
-
-int intel_gmch_bridge_setup(struct drm_i915_private *i915);
-void intel_gmch_bar_setup(struct drm_i915_private *i915);
-void intel_gmch_bar_teardown(struct drm_i915_private *i915);
-int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode);
-unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode);
-
-#endif /* __INTEL_GMCH_H__ */
diff --git a/drivers/gpu/drm/i915/vlv_suspend.c b/drivers/gpu/drm/i915/vlv_suspend.c
index 221e4c0b2c58..bace7b38329b 100644
--- a/drivers/gpu/drm/i915/vlv_suspend.c
+++ b/drivers/gpu/drm/i915/vlv_suspend.c
@@ -453,7 +453,7 @@ int vlv_resume_prepare(struct drm_i915_private *dev_priv, bool rpm_resume)
vlv_check_no_gt_access(dev_priv);
if (rpm_resume)
- intel_clock_gating_init(dev_priv);
+ intel_clock_gating_init(&dev_priv->drm);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index c063756eaea3..80493224eb6c 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -837,7 +837,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
static int
nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *passed_fb,
- int x, int y, bool atomic)
+ int x, int y)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -850,19 +850,12 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
NV_DEBUG(drm, "index %d\n", nv_crtc->index);
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
NV_DEBUG(drm, "No FB bound\n");
return 0;
}
- /* If atomic, we want to switch to the fb we were passed, so
- * now we update pointers to do that.
- */
- if (atomic) {
- drm_fb = passed_fb;
- } else {
- drm_fb = crtc->primary->fb;
- }
+ drm_fb = crtc->primary->fb;
nvbo = nouveau_gem_object(drm_fb->obj[0]);
nv_crtc->fb.offset = nvbo->offset;
@@ -920,15 +913,7 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
int ret = nv_crtc_swap_fbs(crtc, old_fb);
if (ret)
return ret;
- return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
-}
-
-static int
-nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
+ return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y);
}
static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src,
@@ -1274,7 +1259,6 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
.commit = nv_crtc_commit,
.mode_set = nv_crtc_mode_set,
.mode_set_base = nv04_crtc_mode_set_base,
- .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
.disable = nv_crtc_disable,
.get_scanout_position = nouveau_display_scanoutpos,
};
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 76f6af819037..307152ad7759 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -781,6 +781,19 @@ config DRM_PANEL_SAMSUNG_LD9040
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
+config DRM_PANEL_SAMSUNG_LTL106HL02
+ tristate "Samsung LTL106HL02 panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for the Samsung LTL106HL02
+ panel driver which is used in Microsoft Surface 2.
+
+ To compile this driver as a module, choose M here: the module
+ will be called panel-samsung-ltl106hl02.
+
config DRM_PANEL_SAMSUNG_S6E3FA7
tristate "Samsung S6E3FA7 panel driver"
depends on OF
@@ -1165,6 +1178,7 @@ config DRM_PANEL_VISIONOX_RM69299
tristate "Visionox RM69299"
depends on OF
depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Visionox
RM69299 DSI Video Mode panel.
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index b9562a6fdcb3..aeffaa95666d 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS639RQ08) += panel-samsung-ams639rq08.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_LTL106HL02) += panel-samsung-ltl106hl02.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 415b894890ad..85dd3f4cb8e1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1880,6 +1880,7 @@ static const struct panel_delay delay_80_500_e50_d50 = {
*/
static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"),
+ EDP_PANEL_ENTRY('A', 'U', 'O', 0x0ba4, &delay_200_500_e50, "B140QAX01.H"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
@@ -1904,6 +1905,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"),
+ EDP_PANEL_ENTRY('A', 'U', 'O', 0x643d, &delay_200_500_e50, "B140HAN06.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"),
@@ -2033,6 +2035,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1462, &delay_200_500_e50, "MNE007QS5-2"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1468, &delay_200_500_e50, "MNE007QB2-2"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"),
+ EDP_PANEL_ENTRY('C', 'S', 'W', 0x147c, &delay_200_500_e50_d100, "MNE007QB3-1"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1519, &delay_200_500_e80_d50, "MNF601BS1-3"),
EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"),
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
index 46a56ea92ad9..293826c5006b 100644
--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -20,13 +20,18 @@
#include <drm/display/drm_dsc.h>
#include <drm/display/drm_dsc_helper.h>
-#define NUM_SUPPLIES 2
+static const struct regulator_bulk_data sw43408_supplies[] = {
+ { .supply = "vddi", /* 1.8 V */
+ .init_load_uA = 62000 },
+ { .supply = "vpnl", /* 3.0 V */
+ .init_load_uA = 857000 },
+};
struct sw43408_panel {
struct drm_panel base;
struct mipi_dsi_device *link;
- struct regulator_bulk_data supplies[NUM_SUPPLIES];
+ struct regulator_bulk_data *supplies;
struct gpio_desc *reset_gpio;
@@ -52,7 +57,7 @@ static int sw43408_unprepare(struct drm_panel *panel)
gpiod_set_value(sw43408->reset_gpio, 1);
- ret = regulator_bulk_disable(ARRAY_SIZE(sw43408->supplies), sw43408->supplies);
+ ret = regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), sw43408->supplies);
return ret ? : ctx.accum_err;
}
@@ -119,23 +124,28 @@ static int sw43408_program(struct drm_panel *panel)
return ctx.accum_err;
}
+static void sw43408_reset(struct sw43408_panel *ctx)
+{
+ gpiod_set_value(ctx->reset_gpio, 0);
+ usleep_range(9000, 10000);
+ gpiod_set_value(ctx->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ gpiod_set_value(ctx->reset_gpio, 0);
+ usleep_range(9000, 10000);
+}
+
static int sw43408_prepare(struct drm_panel *panel)
{
struct sw43408_panel *ctx = to_panel_info(panel);
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ ret = regulator_bulk_enable(ARRAY_SIZE(sw43408_supplies), ctx->supplies);
if (ret < 0)
return ret;
usleep_range(5000, 6000);
- gpiod_set_value(ctx->reset_gpio, 0);
- usleep_range(9000, 10000);
- gpiod_set_value(ctx->reset_gpio, 1);
- usleep_range(1000, 2000);
- gpiod_set_value(ctx->reset_gpio, 0);
- usleep_range(9000, 10000);
+ sw43408_reset(ctx);
ret = sw43408_program(panel);
if (ret)
@@ -145,11 +155,11 @@ static int sw43408_prepare(struct drm_panel *panel)
poweroff:
gpiod_set_value(ctx->reset_gpio, 1);
- regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), ctx->supplies);
return ret;
}
-static const struct drm_display_mode sw43408_mode = {
+static const struct drm_display_mode lh546wf1_ed01_mode = {
.clock = (1080 + 20 + 32 + 20) * (2160 + 20 + 4 + 20) * 60 / 1000,
.hdisplay = 1080,
@@ -171,7 +181,7 @@ static const struct drm_display_mode sw43408_mode = {
static int sw43408_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
- return drm_connector_helper_get_modes_fixed(connector, &sw43408_mode);
+ return drm_connector_helper_get_modes_fixed(connector, &lh546wf1_ed01_mode);
}
static int sw43408_backlight_update_status(struct backlight_device *bl)
@@ -214,7 +224,8 @@ static const struct drm_panel_funcs sw43408_funcs = {
};
static const struct of_device_id sw43408_of_match[] = {
- { .compatible = "lg,sw43408", },
+ { .compatible = "lg,sw43408", }, /* legacy */
+ { .compatible = "lg,sw43408-lh546wf1-ed01", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sw43408_of_match);
@@ -224,20 +235,17 @@ static int sw43408_add(struct sw43408_panel *ctx)
struct device *dev = &ctx->link->dev;
int ret;
- ctx->supplies[0].supply = "vddi"; /* 1.88 V */
- ctx->supplies[0].init_load_uA = 62000;
- ctx->supplies[1].supply = "vpnl"; /* 3.0 V */
- ctx->supplies[1].init_load_uA = 857000;
-
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
- ctx->supplies);
+ ret = devm_regulator_bulk_get_const(dev,
+ ARRAY_SIZE(sw43408_supplies),
+ sw43408_supplies,
+ &ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- ret = PTR_ERR(ctx->reset_gpio);
- return dev_err_probe(dev, ret, "cannot get reset gpio\n");
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
}
ret = sw43408_backlight_init(ctx);
@@ -294,10 +302,6 @@ static void sw43408_remove(struct mipi_dsi_device *dsi)
struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
- ret = sw43408_unprepare(&ctx->base);
- if (ret < 0)
- dev_err(&dsi->dev, "failed to unprepare panel: %d\n", ret);
-
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index a0f58c3b73f6..60701521c3b1 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -109,177 +109,140 @@ static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel)
return container_of(panel, struct otm8009a, panel);
}
-static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data,
- size_t len)
-{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
-
- if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0)
- dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n");
-}
-
-#define dcs_write_seq(ctx, seq...) \
-({ \
- static const u8 d[] = { seq }; \
- otm8009a_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \
-})
-
#define dcs_write_cmd_at(ctx, cmd, seq...) \
({ \
- dcs_write_seq(ctx, MCS_ADRSFT, (cmd) & 0xFF); \
- dcs_write_seq(ctx, (cmd) >> 8, seq); \
+ mipi_dsi_dcs_write_seq_multi(ctx, MCS_ADRSFT, (cmd) & 0xFF); \
+ mipi_dsi_dcs_write_seq_multi(ctx, (cmd) >> 8, seq); \
})
static int otm8009a_init_sequence(struct otm8009a *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- int ret;
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
/* Enter CMD2 */
- dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0x80, 0x09, 0x01);
+ dcs_write_cmd_at(&dsi_ctx, MCS_CMD2_ENA1, 0x80, 0x09, 0x01);
/* Enter Orise Command2 */
- dcs_write_cmd_at(ctx, MCS_CMD2_ENA2, 0x80, 0x09);
-
- dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL, 0x30);
- mdelay(10);
-
- dcs_write_cmd_at(ctx, MCS_NO_DOC1, 0x40);
- mdelay(10);
-
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL4 + 1, 0xA9);
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 1, 0x34);
- dcs_write_cmd_at(ctx, MCS_P_DRV_M, 0x50);
- dcs_write_cmd_at(ctx, MCS_VCOMDC, 0x4E);
- dcs_write_cmd_at(ctx, MCS_OSC_ADJ, 0x66); /* 65Hz */
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 2, 0x01);
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 5, 0x34);
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 4, 0x33);
- dcs_write_cmd_at(ctx, MCS_GVDDSET, 0x79, 0x79);
- dcs_write_cmd_at(ctx, MCS_SD_CTRL + 1, 0x1B);
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 2, 0x83);
- dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL + 1, 0x83);
- dcs_write_cmd_at(ctx, MCS_RGB_VID_SET, 0x0E);
- dcs_write_cmd_at(ctx, MCS_PANSET, 0x00, 0x01);
-
- dcs_write_cmd_at(ctx, MCS_GOAVST, 0x85, 0x01, 0x00, 0x84, 0x01, 0x00);
- dcs_write_cmd_at(ctx, MCS_GOACLKA1, 0x18, 0x04, 0x03, 0x39, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_CMD2_ENA2, 0x80, 0x09);
+
+ dcs_write_cmd_at(&dsi_ctx, MCS_SD_PCH_CTRL, 0x30);
+ mipi_dsi_msleep(&dsi_ctx, 10);
+
+ dcs_write_cmd_at(&dsi_ctx, MCS_NO_DOC1, 0x40);
+ mipi_dsi_msleep(&dsi_ctx, 10);
+
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL4 + 1, 0xA9);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL2 + 1, 0x34);
+ dcs_write_cmd_at(&dsi_ctx, MCS_P_DRV_M, 0x50);
+ dcs_write_cmd_at(&dsi_ctx, MCS_VCOMDC, 0x4E);
+ dcs_write_cmd_at(&dsi_ctx, MCS_OSC_ADJ, 0x66); /* 65Hz */
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL2 + 2, 0x01);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL2 + 5, 0x34);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL2 + 4, 0x33);
+ dcs_write_cmd_at(&dsi_ctx, MCS_GVDDSET, 0x79, 0x79);
+ dcs_write_cmd_at(&dsi_ctx, MCS_SD_CTRL + 1, 0x1B);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL1 + 2, 0x83);
+ dcs_write_cmd_at(&dsi_ctx, MCS_SD_PCH_CTRL + 1, 0x83);
+ dcs_write_cmd_at(&dsi_ctx, MCS_RGB_VID_SET, 0x0E);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANSET, 0x00, 0x01);
+
+ dcs_write_cmd_at(&dsi_ctx, MCS_GOAVST, 0x85, 0x01, 0x00, 0x84, 0x01, 0x00);
+ dcs_write_cmd_at(&dsi_ctx, MCS_GOACLKA1, 0x18, 0x04, 0x03, 0x39, 0x00, 0x00,
0x00, 0x18, 0x03, 0x03, 0x3A, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_GOACLKA3, 0x18, 0x02, 0x03, 0x3B, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_GOACLKA3, 0x18, 0x02, 0x03, 0x3B, 0x00, 0x00,
0x00, 0x18, 0x01, 0x03, 0x3C, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_GOAECLK, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_GOAECLK, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00,
0x01, 0x02, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_NO_DOC2, 0x00);
+ dcs_write_cmd_at(&dsi_ctx, MCS_NO_DOC2, 0x00);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET5, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET5, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET6, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET6, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
4, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- dcs_write_cmd_at(ctx, MCS_PANCTRLSET8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANCTRLSET8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
- dcs_write_cmd_at(ctx, MCS_PANU2D1, 0x00, 0x26, 0x09, 0x0B, 0x01, 0x25,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANU2D1, 0x00, 0x26, 0x09, 0x0B, 0x01, 0x25,
0x00, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_PANU2D2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANU2D2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0A, 0x0C, 0x02);
- dcs_write_cmd_at(ctx, MCS_PANU2D3, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PANU2D3, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_PAND2U1, 0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PAND2U1, 0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26,
0x00, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_PAND2U2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PAND2U2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0B, 0x09, 0x01);
- dcs_write_cmd_at(ctx, MCS_PAND2U3, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ dcs_write_cmd_at(&dsi_ctx, MCS_PAND2U3, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 1, 0x66);
+ dcs_write_cmd_at(&dsi_ctx, MCS_PWR_CTRL1 + 1, 0x66);
- dcs_write_cmd_at(ctx, MCS_NO_DOC3, 0x06);
+ dcs_write_cmd_at(&dsi_ctx, MCS_NO_DOC3, 0x06);
- dcs_write_cmd_at(ctx, MCS_GMCT2_2P, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
+ dcs_write_cmd_at(&dsi_ctx, MCS_GMCT2_2P, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A,
0x01);
- dcs_write_cmd_at(ctx, MCS_GMCT2_2N, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
+ dcs_write_cmd_at(&dsi_ctx, MCS_GMCT2_2N, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A,
0x01);
/* Exit CMD2 */
- dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0xFF, 0xFF, 0xFF);
+ dcs_write_cmd_at(&dsi_ctx, MCS_CMD2_ENA1, 0xFF, 0xFF, 0xFF);
- ret = mipi_dsi_dcs_nop(dsi);
- if (ret)
- return ret;
-
- ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
- if (ret)
- return ret;
+ mipi_dsi_dcs_nop_multi(&dsi_ctx);
- /* Wait for sleep out exit */
- mdelay(120);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
/* Default portrait 480x800 rgb24 */
- dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
- ret = mipi_dsi_dcs_set_column_address(dsi, 0, OTM8009A_HDISPLAY - 1);
- if (ret)
- return ret;
+ mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0, OTM8009A_HDISPLAY - 1);
- ret = mipi_dsi_dcs_set_page_address(dsi, 0, OTM8009A_VDISPLAY - 1);
- if (ret)
- return ret;
+ mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0, OTM8009A_VDISPLAY - 1);
/* See otm8009a driver documentation for pixel format descriptions */
- ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
+ mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, MIPI_DCS_PIXEL_FMT_24BIT |
MIPI_DCS_PIXEL_FMT_24BIT << 4);
- if (ret)
- return ret;
/* Disable CABC feature */
- dcs_write_seq(ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
- ret = mipi_dsi_dcs_set_display_on(dsi);
- if (ret)
- return ret;
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
- ret = mipi_dsi_dcs_nop(dsi);
- if (ret)
- return ret;
+ mipi_dsi_dcs_nop_multi(&dsi_ctx);
/* Send Command GRAM memory write (no parameters) */
- dcs_write_seq(ctx, MIPI_DCS_WRITE_MEMORY_START);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START);
/* Wait a short while to let the panel be ready before the 1st frame */
- mdelay(10);
+ mipi_dsi_msleep(&dsi_ctx, 10);
- return 0;
+ return dsi_ctx.accum_err;
}
static int otm8009a_disable(struct drm_panel *panel)
{
struct otm8009a *ctx = panel_to_otm8009a(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- int ret;
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
backlight_disable(ctx->bl_dev);
- ret = mipi_dsi_dcs_set_display_off(dsi);
- if (ret)
- return ret;
-
- ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
- if (ret)
- return ret;
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
- msleep(120);
-
- return 0;
+ return dsi_ctx.accum_err;
}
static int otm8009a_unprepare(struct drm_panel *panel)
@@ -383,6 +346,8 @@ static const struct drm_panel_funcs otm8009a_drm_funcs = {
static int otm8009a_backlight_update_status(struct backlight_device *bd)
{
struct otm8009a *ctx = bl_get_data(bd);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
u8 data[2];
if (!ctx->prepared) {
@@ -397,7 +362,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
*/
data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS;
data[1] = bd->props.brightness;
- otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data));
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, data, ARRAY_SIZE(data));
/* set Brightness Control & Backlight on */
data[1] = 0x24;
@@ -409,9 +374,9 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
/* Update Brightness Control & Backlight */
data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY;
- otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data));
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, data, ARRAY_SIZE(data));
- return 0;
+ return dsi_ctx.accum_err;
}
static const struct backlight_ops otm8009a_backlight_ops = {
diff --git a/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c b/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c
new file mode 100644
index 000000000000..1618841b7caa
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+struct samsung_ltl106hl02 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct samsung_ltl106hl02 *to_samsung_ltl106hl02(struct drm_panel *panel)
+{
+ return container_of(panel, struct samsung_ltl106hl02, panel);
+}
+
+static void samsung_ltl106hl02_reset(struct samsung_ltl106hl02 *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(2000, 3000);
+}
+
+static int samsung_ltl106hl02_prepare(struct drm_panel *panel)
+{
+ struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_enable(ctx->supply);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable power supply %d\n", ret);
+ return ret;
+ }
+
+ if (ctx->reset_gpio)
+ samsung_ltl106hl02_reset(ctx);
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 70);
+
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 5);
+
+ return dsi_ctx.accum_err;
+}
+
+static int samsung_ltl106hl02_unprepare(struct drm_panel *panel)
+{
+ struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 50);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 150);
+
+ if (ctx->reset_gpio)
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ regulator_disable(ctx->supply);
+
+ return 0;
+}
+
+static const struct drm_display_mode samsung_ltl106hl02_mode = {
+ .clock = (1920 + 32 + 32 + 64) * (1080 + 6 + 3 + 22) * 60 / 1000,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 32,
+ .hsync_end = 1920 + 32 + 32,
+ .htotal = 1920 + 32 + 32 + 64,
+ .vdisplay = 1080,
+ .vsync_start = 1080 + 6,
+ .vsync_end = 1080 + 6 + 3,
+ .vtotal = 1080 + 6 + 3 + 22,
+ .width_mm = 235,
+ .height_mm = 132,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int samsung_ltl106hl02_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &samsung_ltl106hl02_mode);
+}
+
+static const struct drm_panel_funcs samsung_ltl106hl02_panel_funcs = {
+ .prepare = samsung_ltl106hl02_prepare,
+ .unprepare = samsung_ltl106hl02_unprepare,
+ .get_modes = samsung_ltl106hl02_get_modes,
+};
+
+static int samsung_ltl106hl02_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct samsung_ltl106hl02 *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct samsung_ltl106hl02, panel,
+ &samsung_ltl106hl02_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(ctx->supply))
+ return dev_err_probe(dev, PTR_ERR(ctx->supply),
+ "Failed to get power regulator\n");
+
+ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = devm_mipi_dsi_attach(dev, dsi);
+ if (ret < 0) {
+ drm_panel_remove(&ctx->panel);
+ return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+ }
+
+ return 0;
+}
+
+static void samsung_ltl106hl02_remove(struct mipi_dsi_device *dsi)
+{
+ struct samsung_ltl106hl02 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id samsung_ltl106hl02_of_match[] = {
+ { .compatible = "samsung,ltl106hl02-001" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, samsung_ltl106hl02_of_match);
+
+static struct mipi_dsi_driver samsung_ltl106hl02_driver = {
+ .driver = {
+ .name = "panel-samsung-ltl106hl02",
+ .of_match_table = samsung_ltl106hl02_of_match,
+ },
+ .probe = samsung_ltl106hl02_probe,
+ .remove = samsung_ltl106hl02_remove,
+};
+module_mipi_dsi_driver(samsung_ltl106hl02_driver);
+
+MODULE_AUTHOR("Anton Bambura <jenneron@protonmail.com>");
+MODULE_DESCRIPTION("DRM driver for Samsung LTL106HL02 video mode DSI panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index b26b682826bc..3acc9f3dac16 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2509,6 +2509,31 @@ static const struct panel_desc hannstar_hsd101pww2 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
+static const struct display_timing hannstar_hsd156juw2_timing = {
+ .pixelclock = { 66000000, 72800000, 80500000 },
+ .hactive = { 1920, 1920, 1920 },
+ .hfront_porch = { 20, 30, 30 },
+ .hback_porch = { 20, 30, 30 },
+ .hsync_len = { 50, 60, 90 },
+ .vactive = { 1080, 1080, 1080 },
+ .vfront_porch = { 1, 2, 4 },
+ .vback_porch = { 1, 2, 4 },
+ .vsync_len = { 3, 40, 80 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc hannstar_hsd156juw2 = {
+ .timings = &hannstar_hsd156juw2_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 344,
+ .height = 194,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
.clock = 33333,
.hdisplay = 800,
@@ -5254,6 +5279,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "hannstar,hsd101pww2",
.data = &hannstar_hsd101pww2,
}, {
+ .compatible = "hannstar,hsd156juw2",
+ .data = &hannstar_hsd156juw2,
+ }, {
.compatible = "hit,tx23d38vm0caa",
.data = &hitachi_tx23d38vm0caa
}, {
diff --git a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c
index 7c989b70ab51..a14c86c60d19 100644
--- a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c
+++ b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c
@@ -212,6 +212,8 @@ static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi)
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
+ ctx->panel.prepare_prev_first = true;
+
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index c61b97af120c..dedc13e56631 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -12,6 +12,7 @@
#include "panfrost_device.h"
#include "panfrost_devfreq.h"
#include "panfrost_features.h"
+#include "panfrost_gem.h"
#include "panfrost_issues.h"
#include "panfrost_gpu.h"
#include "panfrost_job.h"
@@ -267,6 +268,8 @@ int panfrost_device_init(struct panfrost_device *pfdev)
if (err)
goto out_job;
+ panfrost_gem_init(pfdev);
+
return 0;
out_job:
panfrost_jm_fini(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index e61c4329fd07..0f3992412205 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -79,6 +79,7 @@ struct panfrost_features {
u32 thread_max_workgroup_sz;
u32 thread_max_barrier_sz;
u32 coherency_features;
+ u32 selected_coherency;
u32 afbc_features;
u32 texture_features[4];
u32 js_features[16];
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 7d8c7c337606..b95120682a72 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -95,6 +95,7 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct
PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15);
PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups);
PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc);
+ PANFROST_FEATURE(SELECTED_COHERENCY, selected_coherency);
case DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP:
ret = panfrost_ioctl_query_timestamp(pfdev, &param->value);
@@ -125,6 +126,10 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct
return 0;
}
+#define PANFROST_BO_FLAGS (PANFROST_BO_NOEXEC | \
+ PANFROST_BO_HEAP | \
+ PANFROST_BO_WB_MMAP)
+
static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
struct drm_file *file)
{
@@ -134,8 +139,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
struct panfrost_gem_mapping *mapping;
int ret;
- if (!args->size || args->pad ||
- (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP)))
+ if (!args->size || args->pad || (args->flags & ~PANFROST_BO_FLAGS))
return -EINVAL;
/* Heaps should never be executable */
@@ -579,6 +583,91 @@ static int panfrost_ioctl_jm_ctx_destroy(struct drm_device *dev, void *data,
return panfrost_jm_ctx_destroy(file, args->handle);
}
+static int panfrost_ioctl_sync_bo(struct drm_device *ddev, void *data,
+ struct drm_file *file)
+{
+ struct drm_panfrost_sync_bo *args = data;
+ struct drm_panfrost_bo_sync_op *ops;
+ struct drm_gem_object *obj;
+ int ret;
+ u32 i;
+
+ if (args->pad)
+ return -EINVAL;
+
+ if (!args->op_count)
+ return 0;
+
+ ops = kvmalloc_array(args->op_count, sizeof(*ops), GFP_KERNEL);
+ if (!ops) {
+ DRM_DEBUG("Failed to allocate incoming BO sync ops array\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(ops, (void __user *)(uintptr_t)args->ops,
+ args->op_count * sizeof(*ops))) {
+ DRM_DEBUG("Failed to copy in BO sync ops\n");
+ ret = -EFAULT;
+ goto err_ops;
+ }
+
+ for (i = 0; i < args->op_count; i++) {
+ obj = drm_gem_object_lookup(file, ops[i].handle);
+ if (!obj) {
+ ret = -ENOENT;
+ goto err_ops;
+ }
+
+ ret = panfrost_gem_sync(obj, ops[i].type,
+ ops[i].offset, ops[i].size);
+
+ drm_gem_object_put(obj);
+
+ if (ret)
+ goto err_ops;
+ }
+
+err_ops:
+ kvfree(ops);
+
+ return ret;
+}
+
+static int panfrost_ioctl_query_bo_info(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_panfrost_query_bo_info *args = data;
+ struct drm_gem_object *gem_obj;
+ struct panfrost_gem_object *bo;
+
+ gem_obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
+ return -ENOENT;
+ }
+
+ bo = to_panfrost_bo(gem_obj);
+ args->pad = 0;
+ args->create_flags = 0;
+ args->extra_flags = 0;
+
+ if (drm_gem_is_imported(gem_obj)) {
+ args->extra_flags |= DRM_PANFROST_BO_IS_IMPORTED;
+ } else {
+ if (bo->noexec)
+ args->create_flags |= PANFROST_BO_NOEXEC;
+
+ if (bo->is_heap)
+ args->create_flags |= PANFROST_BO_HEAP;
+
+ if (!bo->base.map_wc)
+ args->create_flags |= PANFROST_BO_WB_MMAP;
+ }
+
+ drm_gem_object_put(gem_obj);
+ return 0;
+}
+
int panfrost_unstable_ioctl_check(void)
{
if (!unstable_ioctls)
@@ -648,6 +737,8 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
PANFROST_IOCTL(SET_LABEL_BO, set_label_bo, DRM_RENDER_ALLOW),
PANFROST_IOCTL(JM_CTX_CREATE, jm_ctx_create, DRM_RENDER_ALLOW),
PANFROST_IOCTL(JM_CTX_DESTROY, jm_ctx_destroy, DRM_RENDER_ALLOW),
+ PANFROST_IOCTL(SYNC_BO, sync_bo, DRM_RENDER_ALLOW),
+ PANFROST_IOCTL(QUERY_BO_INFO, query_bo_info, DRM_RENDER_ALLOW),
};
static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev,
@@ -837,6 +928,9 @@ static void panfrost_debugfs_init(struct drm_minor *minor)
* - 1.4 - adds SET_LABEL_BO
* - 1.5 - adds JM_CTX_{CREATE,DESTROY} ioctls and extend SUBMIT to allow
* context creation with configurable priorities/affinity
+ * - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO,
+ * PANFROST_IOCTL_QUERY_BO_INFO and
+ * DRM_PANFROST_PARAM_SELECTED_COHERENCY
*/
static const struct drm_driver panfrost_drm_driver = {
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
@@ -849,15 +943,22 @@ static const struct drm_driver panfrost_drm_driver = {
.name = "panfrost",
.desc = "panfrost DRM",
.major = 1,
- .minor = 5,
+ .minor = 6,
.gem_create_object = panfrost_gem_create_object,
+ .gem_prime_import = panfrost_gem_prime_import,
.gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = panfrost_debugfs_init,
#endif
};
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+bool panfrost_transparent_hugepage = true;
+module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
+#endif
+
static int panfrost_probe(struct platform_device *pdev)
{
struct panfrost_device *pfdev;
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.h b/drivers/gpu/drm/panfrost/panfrost_drv.h
new file mode 100644
index 000000000000..a2277ec61aab
--- /dev/null
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
+
+#ifndef __PANFROST_DRV_H__
+#define __PANFROST_DRV_H__
+
+extern bool panfrost_transparent_hugepage;
+
+#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 8041b65c6609..44985b515212 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
#include <linux/cleanup.h>
#include <linux/err.h>
@@ -10,9 +11,26 @@
#include <drm/panfrost_drm.h>
#include <drm/drm_print.h>
#include "panfrost_device.h"
+#include "panfrost_drv.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
+void panfrost_gem_init(struct panfrost_device *pfdev)
+{
+ int err;
+
+ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
+ !panfrost_transparent_hugepage)
+ return;
+
+ err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
+ if (drm_gem_get_huge_mnt(&pfdev->base))
+ drm_info(&pfdev->base, "Using Transparent Hugepage\n");
+ else if (err)
+ drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
+ err);
+}
+
#ifdef CONFIG_DEBUG_FS
static void panfrost_gem_debugfs_bo_add(struct panfrost_device *pfdev,
struct panfrost_gem_object *bo)
@@ -259,6 +277,128 @@ static size_t panfrost_gem_rss(struct drm_gem_object *obj)
return 0;
}
+static struct sg_table *
+panfrost_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
+ enum dma_data_direction dir)
+{
+ struct sg_table *sgt = drm_gem_map_dma_buf(attach, dir);
+
+ if (!IS_ERR(sgt))
+ attach->priv = sgt;
+
+ return sgt;
+}
+
+static void
+panfrost_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+{
+ attach->priv = NULL;
+ drm_gem_unmap_dma_buf(attach, sgt, dir);
+}
+
+static int
+panfrost_gem_prime_begin_cpu_access(struct dma_buf *dma_buf,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+ struct dma_buf_attachment *attach;
+
+ dma_resv_lock(obj->resv, NULL);
+ if (shmem->sgt)
+ dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir);
+
+ if (shmem->vaddr)
+ invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size);
+
+ list_for_each_entry(attach, &dma_buf->attachments, node) {
+ struct sg_table *sgt = attach->priv;
+
+ if (sgt)
+ dma_sync_sgtable_for_cpu(attach->dev, sgt, dir);
+ }
+ dma_resv_unlock(obj->resv);
+
+ return 0;
+}
+
+static int
+panfrost_gem_prime_end_cpu_access(struct dma_buf *dma_buf,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+ struct dma_buf_attachment *attach;
+
+ dma_resv_lock(obj->resv, NULL);
+ list_for_each_entry(attach, &dma_buf->attachments, node) {
+ struct sg_table *sgt = attach->priv;
+
+ if (sgt)
+ dma_sync_sgtable_for_device(attach->dev, sgt, dir);
+ }
+
+ if (shmem->vaddr)
+ flush_kernel_vmap_range(shmem->vaddr, shmem->base.size);
+
+ if (shmem->sgt)
+ dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir);
+
+ dma_resv_unlock(obj->resv);
+ return 0;
+}
+
+static const struct dma_buf_ops panfrost_dma_buf_ops = {
+ .attach = drm_gem_map_attach,
+ .detach = drm_gem_map_detach,
+ .map_dma_buf = panfrost_gem_prime_map_dma_buf,
+ .unmap_dma_buf = panfrost_gem_prime_unmap_dma_buf,
+ .release = drm_gem_dmabuf_release,
+ .mmap = drm_gem_dmabuf_mmap,
+ .vmap = drm_gem_dmabuf_vmap,
+ .vunmap = drm_gem_dmabuf_vunmap,
+ .begin_cpu_access = panfrost_gem_prime_begin_cpu_access,
+ .end_cpu_access = panfrost_gem_prime_end_cpu_access,
+};
+
+static struct dma_buf *
+panfrost_gem_prime_export(struct drm_gem_object *obj, int flags)
+{
+ struct drm_device *dev = obj->dev;
+ struct dma_buf_export_info exp_info = {
+ .exp_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .ops = &panfrost_dma_buf_ops,
+ .size = obj->size,
+ .flags = flags,
+ .priv = obj,
+ .resv = obj->resv,
+ };
+
+ return drm_gem_dmabuf_export(dev, &exp_info);
+}
+
+struct drm_gem_object *
+panfrost_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+
+ if (dma_buf->ops == &panfrost_dma_buf_ops && obj->dev == dev) {
+ /* Importing dmabuf exported from our own gem increases
+ * refcount on gem itself instead of f_count of dmabuf.
+ */
+ drm_gem_object_get(obj);
+ return obj;
+ }
+
+ return drm_gem_prime_import(dev, dma_buf);
+}
+
static const struct drm_gem_object_funcs panfrost_gem_funcs = {
.free = panfrost_gem_free_object,
.open = panfrost_gem_open,
@@ -267,6 +407,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = {
.pin = panfrost_gem_pin,
.unpin = drm_gem_shmem_object_unpin,
.get_sg_table = drm_gem_shmem_object_get_sg_table,
+ .export = panfrost_gem_prime_export,
.vmap = drm_gem_shmem_object_vmap,
.vunmap = drm_gem_shmem_object_vunmap,
.mmap = drm_gem_shmem_object_mmap,
@@ -303,12 +444,42 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t
return &obj->base.base;
}
+static bool
+should_map_wc(struct panfrost_gem_object *bo)
+{
+ struct panfrost_device *pfdev = to_panfrost_device(bo->base.base.dev);
+
+ /* We can't do uncached mappings if the device is coherent,
+ * because the zeroing done by the shmem layer at page allocation
+ * time happens on a cached mapping which isn't CPU-flushed (at least
+ * not on Arm64 where the flush is deferred to PTE setup time, and
+ * only done conditionally based on the mapping permissions). We can't
+ * rely on dma_map_sgtable()/dma_sync_sgtable_for_xxx() either to flush
+ * those, because they are NOPed if dma_dev_coherent() returns true.
+ */
+ if (pfdev->coherent)
+ return false;
+
+ /* Cached mappings are explicitly requested, so no write-combine. */
+ if (bo->wb_mmap)
+ return false;
+
+ /* The default is write-combine. */
+ return true;
+}
+
struct panfrost_gem_object *
panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags)
{
struct drm_gem_shmem_object *shmem;
struct panfrost_gem_object *bo;
+ /* The heap buffer is not supposed to be CPU-visible, so don't allow
+ * WB_MMAP on those.
+ */
+ if ((flags & PANFROST_BO_HEAP) && (flags & PANFROST_BO_WB_MMAP))
+ return ERR_PTR(-EINVAL);
+
/* Round up heap allocations to 2MB to keep fault handling simple */
if (flags & PANFROST_BO_HEAP)
size = roundup(size, SZ_2M);
@@ -320,6 +491,8 @@ panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags)
bo = to_panfrost_bo(&shmem->base);
bo->noexec = !!(flags & PANFROST_BO_NOEXEC);
bo->is_heap = !!(flags & PANFROST_BO_HEAP);
+ bo->wb_mmap = !!(flags & PANFROST_BO_WB_MMAP);
+ bo->base.map_wc = should_map_wc(bo);
return bo;
}
@@ -366,6 +539,90 @@ panfrost_gem_set_label(struct drm_gem_object *obj, const char *label)
kfree_const(old_label);
}
+int
+panfrost_gem_sync(struct drm_gem_object *obj, u32 type, u32 offset, u32 size)
+{
+ struct panfrost_gem_object *bo = to_panfrost_bo(obj);
+ struct drm_gem_shmem_object *shmem = &bo->base;
+ const struct drm_device *dev = shmem->base.dev;
+ struct sg_table *sgt;
+ struct scatterlist *sgl;
+ unsigned int count;
+
+ /* Make sure the range is in bounds. */
+ if (offset + size < offset || offset + size > shmem->base.size)
+ return -EINVAL;
+
+ /* Disallow CPU-cache maintenance on imported buffers. */
+ if (drm_gem_is_imported(&shmem->base))
+ return -EINVAL;
+
+ switch (type) {
+ case PANFROST_BO_SYNC_CPU_CACHE_FLUSH:
+ case PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Don't bother if it's WC-mapped */
+ if (shmem->map_wc)
+ return 0;
+
+ /* Nothing to do if the size is zero. */
+ if (size == 0)
+ return 0;
+
+ sgt = drm_gem_shmem_get_pages_sgt(shmem);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
+
+ for_each_sgtable_dma_sg(sgt, sgl, count) {
+ if (size == 0)
+ break;
+
+ dma_addr_t paddr = sg_dma_address(sgl);
+ size_t len = sg_dma_len(sgl);
+
+ if (len <= offset) {
+ offset -= len;
+ continue;
+ }
+
+ paddr += offset;
+ len -= offset;
+ len = min_t(size_t, len, size);
+ size -= len;
+ offset = 0;
+
+ /* It's unclear whether dma_sync_xxx() is the right API to do CPU
+ * cache maintenance given an IOMMU can register their own
+ * implementation doing more than just CPU cache flushes/invalidation,
+ * and what we really care about here is CPU caches only, but that's
+ * the best we have that is both arch-agnostic and does at least the
+ * CPU cache maintenance on a <page,offset,size> tuple.
+ *
+ * Also, I wish we could do a single
+ *
+ * dma_sync_single_for_device(BIDIR)
+ *
+ * and get a flush+invalidate, but that's not how it's implemented
+ * in practice (at least on arm64), so we have to make it
+ *
+ * dma_sync_single_for_device(TO_DEVICE)
+ * dma_sync_single_for_cpu(FROM_DEVICE)
+ *
+ * for the flush+invalidate case.
+ */
+ dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE);
+ if (type == PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
+ dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE);
+ }
+
+ return 0;
+}
+
void
panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label)
{
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 8de3e76f2717..79d4377019e9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -98,6 +98,11 @@ struct panfrost_gem_object {
bool noexec :1;
bool is_heap :1;
+ /* On coherent devices, this reflects the creation flags, not the true
+ * cacheability attribute of the mapping.
+ */
+ bool wb_mmap :1;
+
#ifdef CONFIG_DEBUG_FS
struct panfrost_gem_debugfs debugfs;
#endif
@@ -124,12 +129,17 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
return container_of(node, struct panfrost_gem_mapping, mmnode);
}
+void panfrost_gem_init(struct panfrost_device *pfdev);
+
struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
struct drm_gem_object *
panfrost_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
struct sg_table *sgt);
+struct drm_gem_object *
+panfrost_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
struct panfrost_gem_object *
panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags);
@@ -148,6 +158,8 @@ int panfrost_gem_shrinker_init(struct drm_device *dev);
void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label);
+int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
+ u32 offset, u32 size);
void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index 483d278eb154..7d555e63e21a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -159,8 +159,8 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev)
pfdev->features.revision >= 0x2000)
quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT;
else if (panfrost_model_eq(pfdev, 0x6000) &&
- pfdev->features.coherency_features == COHERENCY_ACE)
- quirks |= (COHERENCY_ACE_LITE | COHERENCY_ACE) <<
+ pfdev->features.coherency_features == BIT(COHERENCY_ACE))
+ quirks |= (BIT(COHERENCY_ACE_LITE) | BIT(COHERENCY_ACE)) <<
JM_FORCE_COHERENCY_FEATURES_SHIFT;
if (panfrost_has_hw_feature(pfdev, HW_FEATURE_IDVS_GROUP_SIZE))
@@ -263,7 +263,27 @@ static int panfrost_gpu_init_features(struct panfrost_device *pfdev)
pfdev->features.max_threads = gpu_read(pfdev, GPU_THREAD_MAX_THREADS);
pfdev->features.thread_max_workgroup_sz = gpu_read(pfdev, GPU_THREAD_MAX_WORKGROUP_SIZE);
pfdev->features.thread_max_barrier_sz = gpu_read(pfdev, GPU_THREAD_MAX_BARRIER_SIZE);
- pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES);
+
+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_COHERENCY_REG))
+ pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES);
+ else
+ pfdev->features.coherency_features = BIT(COHERENCY_ACE_LITE);
+
+ BUILD_BUG_ON(COHERENCY_ACE_LITE != DRM_PANFROST_GPU_COHERENCY_ACE_LITE);
+ BUILD_BUG_ON(COHERENCY_ACE != DRM_PANFROST_GPU_COHERENCY_ACE);
+ BUILD_BUG_ON(COHERENCY_NONE != DRM_PANFROST_GPU_COHERENCY_NONE);
+
+ if (!pfdev->coherent) {
+ pfdev->features.selected_coherency = COHERENCY_NONE;
+ } else if (pfdev->features.coherency_features & BIT(COHERENCY_ACE)) {
+ pfdev->features.selected_coherency = COHERENCY_ACE;
+ } else if (pfdev->features.coherency_features & BIT(COHERENCY_ACE_LITE)) {
+ pfdev->features.selected_coherency = COHERENCY_ACE_LITE;
+ } else {
+ drm_WARN(&pfdev->base, true, "No known coherency protocol supported");
+ pfdev->features.selected_coherency = COHERENCY_NONE;
+ }
+
pfdev->features.afbc_features = gpu_read(pfdev, GPU_AFBC_FEATURES);
for (i = 0; i < 4; i++)
pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i));
diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h
index 2b8f1617b836..ee15f6bf6e6f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_regs.h
+++ b/drivers/gpu/drm/panfrost/panfrost_regs.h
@@ -102,9 +102,15 @@
#define GPU_L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
#define GPU_L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */
+/* GPU_COHERENCY_FEATURES is a bitmask of BIT(COHERENCY_xxx) values encoding the
+ * set of supported coherency protocols. GPU_COHERENCY_ENABLE is passed a
+ * COHERENCY_xxx value.
+ */
#define GPU_COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */
-#define COHERENCY_ACE_LITE BIT(0)
-#define COHERENCY_ACE BIT(1)
+#define GPU_COHERENCY_ENABLE 0x304 /* (RW) Coherency protocol selection */
+#define COHERENCY_ACE_LITE 0
+#define COHERENCY_ACE 1
+#define COHERENCY_NONE 31
#define GPU_STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */
#define GPU_STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index e133b1e0ad6d..54fbb1aa07c5 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -18,6 +18,7 @@
#include "panthor_devfreq.h"
#include "panthor_device.h"
#include "panthor_fw.h"
+#include "panthor_gem.h"
#include "panthor_gpu.h"
#include "panthor_hw.h"
#include "panthor_mmu.h"
@@ -27,6 +28,12 @@
static int panthor_gpu_coherency_init(struct panthor_device *ptdev)
{
+ BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE);
+ BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE);
+ BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE);
+
+ /* Start with no coherency, and update it if the device is flagged coherent. */
+ ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE;
ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT;
if (!ptdev->coherent)
@@ -36,8 +43,10 @@ static int panthor_gpu_coherency_init(struct panthor_device *ptdev)
* ACE protocol has never been supported for command stream frontend GPUs.
*/
if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) &
- GPU_COHERENCY_PROT_BIT(ACE_LITE)))
+ GPU_COHERENCY_PROT_BIT(ACE_LITE))) {
+ ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE;
return 0;
+ }
drm_err(&ptdev->base, "Coherency not supported by the device");
return -ENOTSUPP;
@@ -294,6 +303,8 @@ int panthor_device_init(struct panthor_device *ptdev)
if (ret)
goto err_unplug_fw;
+ panthor_gem_init(ptdev);
+
/* ~3 frames */
pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50);
pm_runtime_use_autosuspend(ptdev->base.dev);
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index d1d4c50da5bf..165dddfde6ca 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -177,7 +177,8 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride,
PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \
PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \
PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \
- PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs))
+ PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs), \
+ PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size))
/**
* PANTHOR_UOBJ_SET() - Copy a kernel object to a user object.
@@ -901,7 +902,8 @@ static int panthor_ioctl_vm_destroy(struct drm_device *ddev, void *data,
return panthor_vm_pool_destroy_vm(pfile->vms, args->id);
}
-#define PANTHOR_BO_FLAGS DRM_PANTHOR_BO_NO_MMAP
+#define PANTHOR_BO_FLAGS (DRM_PANTHOR_BO_NO_MMAP | \
+ DRM_PANTHOR_BO_WB_MMAP)
static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data,
struct drm_file *file)
@@ -920,6 +922,12 @@ static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data,
goto out_dev_exit;
}
+ if ((args->flags & DRM_PANTHOR_BO_NO_MMAP) &&
+ (args->flags & DRM_PANTHOR_BO_WB_MMAP)) {
+ ret = -EINVAL;
+ goto out_dev_exit;
+ }
+
if (args->exclusive_vm_id) {
vm = panthor_vm_pool_get_vm(pfile->vms, args->exclusive_vm_id);
if (!vm) {
@@ -1396,6 +1404,66 @@ static int panthor_ioctl_set_user_mmio_offset(struct drm_device *ddev,
return 0;
}
+static int panthor_ioctl_bo_sync(struct drm_device *ddev, void *data,
+ struct drm_file *file)
+{
+ struct drm_panthor_bo_sync *args = data;
+ struct drm_panthor_bo_sync_op *ops;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (!args->ops.count)
+ return 0;
+
+ ret = PANTHOR_UOBJ_GET_ARRAY(ops, &args->ops);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < args->ops.count; i++) {
+ obj = drm_gem_object_lookup(file, ops[i].handle);
+ if (!obj) {
+ ret = -ENOENT;
+ goto err_ops;
+ }
+
+ ret = panthor_gem_sync(obj, ops[i].type, ops[i].offset,
+ ops[i].size);
+
+ drm_gem_object_put(obj);
+
+ if (ret)
+ goto err_ops;
+ }
+
+err_ops:
+ kvfree(ops);
+
+ return ret;
+}
+
+static int panthor_ioctl_bo_query_info(struct drm_device *ddev, void *data,
+ struct drm_file *file)
+{
+ struct drm_panthor_bo_query_info *args = data;
+ struct panthor_gem_object *bo;
+ struct drm_gem_object *obj;
+
+ obj = drm_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ bo = to_panthor_bo(obj);
+ args->pad = 0;
+ args->create_flags = bo->flags;
+
+ args->extra_flags = 0;
+ if (drm_gem_is_imported(&bo->base.base))
+ args->extra_flags |= DRM_PANTHOR_BO_IS_IMPORTED;
+
+ drm_gem_object_put(obj);
+ return 0;
+}
+
static int
panthor_open(struct drm_device *ddev, struct drm_file *file)
{
@@ -1470,6 +1538,8 @@ static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = {
PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW),
PANTHOR_IOCTL(BO_SET_LABEL, bo_set_label, DRM_RENDER_ALLOW),
PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, DRM_RENDER_ALLOW),
+ PANTHOR_IOCTL(BO_SYNC, bo_sync, DRM_RENDER_ALLOW),
+ PANTHOR_IOCTL(BO_QUERY_INFO, bo_query_info, DRM_RENDER_ALLOW),
};
static int panthor_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -1559,6 +1629,7 @@ static const struct file_operations panthor_drm_driver_fops = {
.read = drm_read,
.llseek = noop_llseek,
.mmap = panthor_mmap,
+ .get_unmapped_area = drm_gem_get_unmapped_area,
.show_fdinfo = drm_show_fdinfo,
.fop_flags = FOP_UNSIGNED_OFFSET,
};
@@ -1604,6 +1675,11 @@ static void panthor_debugfs_init(struct drm_minor *minor)
* - 1.3 - adds DRM_PANTHOR_GROUP_STATE_INNOCENT flag
* - 1.4 - adds DRM_IOCTL_PANTHOR_BO_SET_LABEL ioctl
* - 1.5 - adds DRM_PANTHOR_SET_USER_MMIO_OFFSET ioctl
+ * - 1.6 - enables GLB_COUNTER_EN
+ * - 1.7 - adds DRM_PANTHOR_BO_WB_MMAP flag
+ * - adds DRM_IOCTL_PANTHOR_BO_SYNC ioctl
+ * - adds DRM_IOCTL_PANTHOR_BO_QUERY_INFO ioctl
+ * - adds drm_panthor_gpu_info::selected_coherency
*/
static const struct drm_driver panthor_drm_driver = {
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ |
@@ -1617,15 +1693,22 @@ static const struct drm_driver panthor_drm_driver = {
.name = "panthor",
.desc = "Panthor DRM driver",
.major = 1,
- .minor = 5,
+ .minor = 7,
.gem_create_object = panthor_gem_create_object,
.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table,
+ .gem_prime_import = panthor_gem_prime_import,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = panthor_debugfs_init,
#endif
};
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+bool panthor_transparent_hugepage = true;
+module_param_named(transparent_hugepage, panthor_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
+#endif
+
static int panthor_probe(struct platform_device *pdev)
{
struct panthor_device *ptdev;
diff --git a/drivers/gpu/drm/panthor/panthor_drv.h b/drivers/gpu/drm/panthor/panthor_drv.h
new file mode 100644
index 000000000000..1bc7ddbad23e
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_drv.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
+
+#ifndef __PANTHOR_DRV_H__
+#define __PANTHOR_DRV_H__
+
+extern bool panthor_transparent_hugepage;
+
+#endif
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 1a5e3c1a27fb..a64ec8756bed 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -1044,7 +1044,8 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
if (panthor_fw_has_glb_state(ptdev))
glb_iface->input->ack_irq_mask |= GLB_STATE_MASK;
- panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN, GLB_IDLE_EN);
+ panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN | GLB_COUNTER_EN,
+ GLB_IDLE_EN | GLB_COUNTER_EN);
panthor_fw_toggle_reqs(glb_iface, req, ack,
GLB_CFG_ALLOC_EN |
GLB_CFG_POWEROFF_TIMER |
@@ -1187,7 +1188,6 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang)
else
ptdev->reset.fast = true;
}
- panthor_fw_stop(ptdev);
panthor_job_irq_suspend(&ptdev->fw->irq);
panthor_fw_stop(ptdev);
@@ -1261,10 +1261,6 @@ void panthor_fw_unplug(struct panthor_device *ptdev)
if (ptdev->fw->irq.irq)
panthor_job_irq_suspend(&ptdev->fw->irq);
- panthor_fw_halt_mcu(ptdev);
- if (!panthor_fw_wait_mcu_halted(ptdev))
- drm_warn(&ptdev->base, "Failed to halt MCU on unplug");
-
panthor_fw_stop(ptdev);
}
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index fbde78db270a..b61908fd508a 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
/* Copyright 2023 Collabora ltd. */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
#include <linux/cleanup.h>
#include <linux/dma-buf.h>
@@ -12,10 +13,27 @@
#include <drm/panthor_drm.h>
#include "panthor_device.h"
+#include "panthor_drv.h"
#include "panthor_fw.h"
#include "panthor_gem.h"
#include "panthor_mmu.h"
+void panthor_gem_init(struct panthor_device *ptdev)
+{
+ int err;
+
+ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
+ !panthor_transparent_hugepage)
+ return;
+
+ err = drm_gem_huge_mnt_create(&ptdev->base, "within_size");
+ if (drm_gem_get_huge_mnt(&ptdev->base))
+ drm_info(&ptdev->base, "Using Transparent Hugepage\n");
+ else if (err)
+ drm_warn(&ptdev->base, "Can't use Transparent Hugepage (%d)\n",
+ err);
+}
+
#ifdef CONFIG_DEBUG_FS
static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo)
{
@@ -59,6 +77,39 @@ static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u
static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {}
#endif
+static bool
+should_map_wc(struct panthor_gem_object *bo, struct panthor_vm *exclusive_vm)
+{
+ struct panthor_device *ptdev = container_of(bo->base.base.dev, struct panthor_device, base);
+
+ /* We can't do uncached mappings if the device is coherent,
+ * because the zeroing done by the shmem layer at page allocation
+ * time happens on a cached mapping which isn't CPU-flushed (at least
+ * not on Arm64 where the flush is deferred to PTE setup time, and
+ * only done conditionally based on the mapping permissions). We can't
+ * rely on dma_map_sgtable()/dma_sync_sgtable_for_xxx() either to flush
+ * those, because they are NOPed if dma_dev_coherent() returns true.
+ *
+ * FIXME: Note that this problem is going to pop up again when we
+ * decide to support mapping buffers with the NO_MMAP flag as
+ * non-shareable (AKA buffers accessed only by the GPU), because we
+ * need the same CPU flush to happen after page allocation, otherwise
+ * there's a risk of data leak or late corruption caused by a dirty
+ * cacheline being evicted. At this point we'll need a way to force
+ * CPU cache maintenance regardless of whether the device is coherent
+ * or not.
+ */
+ if (ptdev->coherent)
+ return false;
+
+ /* Cached mappings are explicitly requested, so no write-combine. */
+ if (bo->flags & DRM_PANTHOR_BO_WB_MMAP)
+ return false;
+
+ /* The default is write-combine. */
+ return true;
+}
+
static void panthor_gem_free_object(struct drm_gem_object *obj)
{
struct panthor_gem_object *bo = to_panthor_bo(obj);
@@ -145,6 +196,7 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
bo = to_panthor_bo(&obj->base);
kbo->obj = &obj->base;
bo->flags = bo_flags;
+ bo->base.map_wc = should_map_wc(bo, vm);
bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm);
drm_gem_object_get(bo->exclusive_vm_root_gem);
bo->base.base.resv = bo->exclusive_vm_root_gem->resv;
@@ -184,14 +236,130 @@ err_free_bo:
return ERR_PTR(ret);
}
+static struct sg_table *
+panthor_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
+ enum dma_data_direction dir)
+{
+ struct sg_table *sgt = drm_gem_map_dma_buf(attach, dir);
+
+ if (!IS_ERR(sgt))
+ attach->priv = sgt;
+
+ return sgt;
+}
+
+static void
+panthor_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+{
+ attach->priv = NULL;
+ drm_gem_unmap_dma_buf(attach, sgt, dir);
+}
+
+static int
+panthor_gem_prime_begin_cpu_access(struct dma_buf *dma_buf,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+ struct dma_buf_attachment *attach;
+
+ dma_resv_lock(obj->resv, NULL);
+ if (shmem->sgt)
+ dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir);
+
+ if (shmem->vaddr)
+ invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size);
+
+ list_for_each_entry(attach, &dma_buf->attachments, node) {
+ struct sg_table *sgt = attach->priv;
+
+ if (sgt)
+ dma_sync_sgtable_for_cpu(attach->dev, sgt, dir);
+ }
+ dma_resv_unlock(obj->resv);
+
+ return 0;
+}
+
+static int
+panthor_gem_prime_end_cpu_access(struct dma_buf *dma_buf,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+ struct dma_buf_attachment *attach;
+
+ dma_resv_lock(obj->resv, NULL);
+ list_for_each_entry(attach, &dma_buf->attachments, node) {
+ struct sg_table *sgt = attach->priv;
+
+ if (sgt)
+ dma_sync_sgtable_for_device(attach->dev, sgt, dir);
+ }
+
+ if (shmem->vaddr)
+ flush_kernel_vmap_range(shmem->vaddr, shmem->base.size);
+
+ if (shmem->sgt)
+ dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir);
+
+ dma_resv_unlock(obj->resv);
+ return 0;
+}
+
+static const struct dma_buf_ops panthor_dma_buf_ops = {
+ .attach = drm_gem_map_attach,
+ .detach = drm_gem_map_detach,
+ .map_dma_buf = panthor_gem_prime_map_dma_buf,
+ .unmap_dma_buf = panthor_gem_prime_unmap_dma_buf,
+ .release = drm_gem_dmabuf_release,
+ .mmap = drm_gem_dmabuf_mmap,
+ .vmap = drm_gem_dmabuf_vmap,
+ .vunmap = drm_gem_dmabuf_vunmap,
+ .begin_cpu_access = panthor_gem_prime_begin_cpu_access,
+ .end_cpu_access = panthor_gem_prime_end_cpu_access,
+};
+
static struct dma_buf *
panthor_gem_prime_export(struct drm_gem_object *obj, int flags)
{
+ struct drm_device *dev = obj->dev;
+ struct dma_buf_export_info exp_info = {
+ .exp_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .ops = &panthor_dma_buf_ops,
+ .size = obj->size,
+ .flags = flags,
+ .priv = obj,
+ .resv = obj->resv,
+ };
+
/* We can't export GEMs that have an exclusive VM. */
if (to_panthor_bo(obj)->exclusive_vm_root_gem)
return ERR_PTR(-EINVAL);
- return drm_gem_prime_export(obj, flags);
+ return drm_gem_dmabuf_export(dev, &exp_info);
+}
+
+struct drm_gem_object *
+panthor_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct drm_gem_object *obj = dma_buf->priv;
+
+ if (dma_buf->ops == &panthor_dma_buf_ops && obj->dev == dev) {
+ /* Importing dmabuf exported from our own gem increases
+ * refcount on gem itself instead of f_count of dmabuf.
+ */
+ drm_gem_object_get(obj);
+ return obj;
+ }
+
+ return drm_gem_prime_import(dev, dma_buf);
}
static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj)
@@ -229,7 +397,6 @@ static const struct drm_gem_object_funcs panthor_gem_funcs = {
*/
struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size)
{
- struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
struct panthor_gem_object *obj;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -237,7 +404,6 @@ struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t
return ERR_PTR(-ENOMEM);
obj->base.base.funcs = &panthor_gem_funcs;
- obj->base.map_wc = !ptdev->coherent;
mutex_init(&obj->label.lock);
panthor_gem_debugfs_bo_init(obj);
@@ -272,6 +438,7 @@ panthor_gem_create_with_handle(struct drm_file *file,
bo = to_panthor_bo(&shmem->base);
bo->flags = flags;
+ bo->base.map_wc = should_map_wc(bo, exclusive_vm);
if (exclusive_vm) {
bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm);
@@ -349,6 +516,91 @@ panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label)
panthor_gem_bo_set_label(bo->obj, str);
}
+int
+panthor_gem_sync(struct drm_gem_object *obj, u32 type,
+ u64 offset, u64 size)
+{
+ struct panthor_gem_object *bo = to_panthor_bo(obj);
+ struct drm_gem_shmem_object *shmem = &bo->base;
+ const struct drm_device *dev = shmem->base.dev;
+ struct sg_table *sgt;
+ struct scatterlist *sgl;
+ unsigned int count;
+
+ /* Make sure the range is in bounds. */
+ if (offset + size < offset || offset + size > shmem->base.size)
+ return -EINVAL;
+
+ /* Disallow CPU-cache maintenance on imported buffers. */
+ if (drm_gem_is_imported(&shmem->base))
+ return -EINVAL;
+
+ switch (type) {
+ case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH:
+ case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Don't bother if it's WC-mapped */
+ if (shmem->map_wc)
+ return 0;
+
+ /* Nothing to do if the size is zero. */
+ if (size == 0)
+ return 0;
+
+ sgt = drm_gem_shmem_get_pages_sgt(shmem);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
+
+ for_each_sgtable_dma_sg(sgt, sgl, count) {
+ if (size == 0)
+ break;
+
+ dma_addr_t paddr = sg_dma_address(sgl);
+ size_t len = sg_dma_len(sgl);
+
+ if (len <= offset) {
+ offset -= len;
+ continue;
+ }
+
+ paddr += offset;
+ len -= offset;
+ len = min_t(size_t, len, size);
+ size -= len;
+ offset = 0;
+
+ /* It's unclear whether dma_sync_xxx() is the right API to do CPU
+ * cache maintenance given an IOMMU can register their own
+ * implementation doing more than just CPU cache flushes/invalidation,
+ * and what we really care about here is CPU caches only, but that's
+ * the best we have that is both arch-agnostic and does at least the
+ * CPU cache maintenance on a <page,offset,size> tuple.
+ *
+ * Also, I wish we could do a single
+ *
+ * dma_sync_single_for_device(BIDIR)
+ *
+ * and get a flush+invalidate, but that's not how it's implemented
+ * in practice (at least on arm64), so we have to make it
+ *
+ * dma_sync_single_for_device(TO_DEVICE)
+ * dma_sync_single_for_cpu(FROM_DEVICE)
+ *
+ * for the flush+invalidate case.
+ */
+ dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE);
+ if (type == DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
+ dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_DEBUG_FS
struct gem_size_totals {
size_t size;
diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
index 80c6e24112d0..22519c570b5a 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.h
+++ b/drivers/gpu/drm/panthor/panthor_gem.h
@@ -136,6 +136,8 @@ struct panthor_gem_object *to_panthor_bo(struct drm_gem_object *obj)
return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base);
}
+void panthor_gem_init(struct panthor_device *ptdev);
+
struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size);
int
@@ -146,6 +148,12 @@ panthor_gem_create_with_handle(struct drm_file *file,
void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label);
void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label);
+int panthor_gem_sync(struct drm_gem_object *obj,
+ u32 type, u64 offset, u64 size);
+
+struct drm_gem_object *
+panthor_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
static inline u64
panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo)
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index 06b231b2460a..057e167468d0 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -51,7 +51,7 @@ struct panthor_gpu {
static void panthor_gpu_coherency_set(struct panthor_device *ptdev)
{
gpu_write(ptdev, GPU_COHERENCY_PROTOCOL,
- ptdev->coherent ? GPU_COHERENCY_PROT_BIT(ACE_LITE) : GPU_COHERENCY_NONE);
+ ptdev->gpu_info.selected_coherency);
}
static void panthor_gpu_l2_config_set(struct panthor_device *ptdev)
@@ -289,38 +289,42 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
int panthor_gpu_flush_caches(struct panthor_device *ptdev,
u32 l2, u32 lsc, u32 other)
{
- bool timedout = false;
unsigned long flags;
+ int ret = 0;
/* Serialize cache flush operations. */
guard(mutex)(&ptdev->gpu->cache_flush_lock);
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
- if (!drm_WARN_ON(&ptdev->base,
- ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
+ if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
+ } else {
+ ret = -EIO;
}
spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
+ if (ret)
+ return ret;
+
if (!wait_event_timeout(ptdev->gpu->reqs_acked,
!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
msecs_to_jiffies(100))) {
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 &&
!(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED))
- timedout = true;
+ ret = -ETIMEDOUT;
else
ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
}
- if (timedout) {
+ if (ret) {
+ panthor_device_schedule_reset(ptdev);
drm_err(&ptdev->base, "Flush caches timeout");
- return -ETIMEDOUT;
}
- return 0;
+ return ret;
}
/**
@@ -360,6 +364,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
return -ETIMEDOUT;
}
+ ptdev->gpu->pending_reqs = 0;
return 0;
}
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index d4839d282689..473a8bebd61e 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -375,6 +375,15 @@ struct panthor_vm {
* flagged as faulty as a result.
*/
bool unhandled_fault;
+
+ /** @locked_region: Information about the currently locked region currently. */
+ struct {
+ /** @locked_region.start: Start of the locked region. */
+ u64 start;
+
+ /** @locked_region.size: Size of the locked region. */
+ u64 size;
+ } locked_region;
};
/**
@@ -510,27 +519,27 @@ static int wait_ready(struct panthor_device *ptdev, u32 as_nr)
return ret;
}
-static int write_cmd(struct panthor_device *ptdev, u32 as_nr, u32 cmd)
+static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd)
{
int status;
/* write AS_COMMAND when MMU is ready to accept another command */
status = wait_ready(ptdev, as_nr);
- if (!status)
+ if (!status) {
gpu_write(ptdev, AS_COMMAND(as_nr), cmd);
+ status = wait_ready(ptdev, as_nr);
+ }
return status;
}
-static void lock_region(struct panthor_device *ptdev, u32 as_nr,
- u64 region_start, u64 size)
+static u64 pack_region_range(struct panthor_device *ptdev, u64 region_start, u64 size)
{
u8 region_width;
- u64 region;
u64 region_end = region_start + size;
- if (!size)
- return;
+ if (drm_WARN_ON_ONCE(&ptdev->base, !size))
+ return 0;
/*
* The locked region is a naturally aligned power of 2 block encoded as
@@ -549,106 +558,51 @@ static void lock_region(struct panthor_device *ptdev, u32 as_nr,
*/
region_start &= GENMASK_ULL(63, region_width);
- region = region_width | region_start;
-
- /* Lock the region that needs to be updated */
- gpu_write64(ptdev, AS_LOCKADDR(as_nr), region);
- write_cmd(ptdev, as_nr, AS_COMMAND_LOCK);
-}
-
-static int mmu_hw_do_operation_locked(struct panthor_device *ptdev, int as_nr,
- u64 iova, u64 size, u32 op)
-{
- const u32 l2_flush_op = CACHE_CLEAN | CACHE_INV;
- u32 lsc_flush_op;
- int ret;
-
- lockdep_assert_held(&ptdev->mmu->as.slots_lock);
-
- switch (op) {
- case AS_COMMAND_FLUSH_MEM:
- lsc_flush_op = CACHE_CLEAN | CACHE_INV;
- break;
- case AS_COMMAND_FLUSH_PT:
- lsc_flush_op = 0;
- break;
- default:
- drm_WARN(&ptdev->base, 1, "Unexpected AS_COMMAND: %d", op);
- return -EINVAL;
- }
-
- if (as_nr < 0)
- return 0;
-
- /*
- * If the AS number is greater than zero, then we can be sure
- * the device is up and running, so we don't need to explicitly
- * power it up
- */
-
- lock_region(ptdev, as_nr, iova, size);
-
- ret = wait_ready(ptdev, as_nr);
- if (ret)
- return ret;
-
- ret = panthor_gpu_flush_caches(ptdev, l2_flush_op, lsc_flush_op, 0);
- if (ret)
- return ret;
-
- /*
- * Explicitly unlock the region as the AS is not unlocked automatically
- * at the end of the GPU_CONTROL cache flush command, unlike
- * AS_COMMAND_FLUSH_MEM or AS_COMMAND_FLUSH_PT.
- */
- write_cmd(ptdev, as_nr, AS_COMMAND_UNLOCK);
-
- /* Wait for the unlock command to complete */
- return wait_ready(ptdev, as_nr);
-}
-
-static int mmu_hw_do_operation(struct panthor_vm *vm,
- u64 iova, u64 size, u32 op)
-{
- struct panthor_device *ptdev = vm->ptdev;
- int ret;
-
- mutex_lock(&ptdev->mmu->as.slots_lock);
- ret = mmu_hw_do_operation_locked(ptdev, vm->as.id, iova, size, op);
- mutex_unlock(&ptdev->mmu->as.slots_lock);
-
- return ret;
+ return region_width | region_start;
}
static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr,
u64 transtab, u64 transcfg, u64 memattr)
{
- int ret;
-
- ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM);
- if (ret)
- return ret;
-
gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab);
gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr);
gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg);
- return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE);
+ return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE);
}
-static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr)
+static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr,
+ bool recycle_slot)
{
+ struct panthor_vm *vm = ptdev->mmu->as.slots[as_nr].vm;
int ret;
- ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM);
+ lockdep_assert_held(&ptdev->mmu->as.slots_lock);
+
+ /* Flush+invalidate RW caches, invalidate RO ones. */
+ ret = panthor_gpu_flush_caches(ptdev, CACHE_CLEAN | CACHE_INV,
+ CACHE_CLEAN | CACHE_INV, CACHE_INV);
if (ret)
return ret;
+ if (vm && vm->locked_region.size) {
+ /* Unlock the region if there's a lock pending. */
+ ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK);
+ if (ret)
+ return ret;
+ }
+
+ /* If the slot is going to be used immediately, don't bother changing
+ * the config.
+ */
+ if (recycle_slot)
+ return 0;
+
gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0);
gpu_write64(ptdev, AS_MEMATTR(as_nr), 0);
gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED);
- return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE);
+ return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE);
}
static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value)
@@ -722,6 +676,10 @@ int panthor_vm_active(struct panthor_vm *vm)
if (refcount_inc_not_zero(&vm->as.active_cnt))
goto out_dev_exit;
+ /* Make sure we don't race with lock/unlock_region() calls
+ * happening around VM bind operations.
+ */
+ mutex_lock(&vm->op_lock);
mutex_lock(&ptdev->mmu->as.slots_lock);
if (refcount_inc_not_zero(&vm->as.active_cnt))
@@ -759,6 +717,11 @@ int panthor_vm_active(struct panthor_vm *vm)
drm_WARN_ON(&ptdev->base, refcount_read(&lru_vm->as.active_cnt));
as = lru_vm->as.id;
+
+ ret = panthor_mmu_as_disable(ptdev, as, true);
+ if (ret)
+ goto out_unlock;
+
panthor_vm_release_as_locked(lru_vm);
}
@@ -789,6 +752,10 @@ out_enable_as:
gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask);
}
+ /* The VM update is guarded by ::op_lock, which we take at the beginning
+ * of this function, so we don't expect any locked region here.
+ */
+ drm_WARN_ON(&vm->ptdev->base, vm->locked_region.size > 0);
ret = panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, vm->memattr);
out_make_active:
@@ -799,6 +766,7 @@ out_make_active:
out_unlock:
mutex_unlock(&ptdev->mmu->as.slots_lock);
+ mutex_unlock(&vm->op_lock);
out_dev_exit:
drm_dev_exit(cookie);
@@ -882,44 +850,64 @@ static size_t get_pgsize(u64 addr, size_t size, size_t *count)
return SZ_2M;
}
-static int panthor_vm_flush_range(struct panthor_vm *vm, u64 iova, u64 size)
+static void panthor_vm_declare_unusable(struct panthor_vm *vm)
{
struct panthor_device *ptdev = vm->ptdev;
- int ret = 0, cookie;
-
- if (vm->as.id < 0)
- return 0;
+ int cookie;
- /* If the device is unplugged, we just silently skip the flush. */
- if (!drm_dev_enter(&ptdev->base, &cookie))
- return 0;
-
- ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT);
+ if (vm->unusable)
+ return;
- drm_dev_exit(cookie);
- return ret;
+ vm->unusable = true;
+ mutex_lock(&ptdev->mmu->as.slots_lock);
+ if (vm->as.id >= 0 && drm_dev_enter(&ptdev->base, &cookie)) {
+ panthor_mmu_as_disable(ptdev, vm->as.id, false);
+ drm_dev_exit(cookie);
+ }
+ mutex_unlock(&ptdev->mmu->as.slots_lock);
}
-static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
+static void panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
{
struct panthor_device *ptdev = vm->ptdev;
struct io_pgtable_ops *ops = vm->pgtbl_ops;
u64 start_iova = iova;
u64 offset = 0;
+ if (!size)
+ return;
+
+ drm_WARN_ON(&ptdev->base,
+ (iova < vm->locked_region.start) ||
+ (iova + size > vm->locked_region.start + vm->locked_region.size));
+
while (offset < size) {
size_t unmapped_sz = 0, pgcount;
size_t pgsize = get_pgsize(iova + offset, size - offset, &pgcount);
unmapped_sz = ops->unmap_pages(ops, iova + offset, pgsize, pgcount, NULL);
+ if (drm_WARN_ON_ONCE(&ptdev->base, unmapped_sz != pgsize * pgcount)) {
+ /* Gracefully handle sparsely unmapped regions to avoid leaving
+ * page table pages behind when the drm_gpuvm and VM page table
+ * are out-of-sync. This is not supposed to happen, hence the
+ * above WARN_ON().
+ */
+ while (!ops->iova_to_phys(ops, iova + unmapped_sz) &&
+ unmapped_sz < pgsize * pgcount)
+ unmapped_sz += SZ_4K;
+
+ /* We're passed the point where we can try to fix things,
+ * so flag the VM unusable to make sure it's not going
+ * to be used anymore.
+ */
+ panthor_vm_declare_unusable(vm);
- if (drm_WARN_ON(&ptdev->base, unmapped_sz != pgsize * pgcount)) {
- drm_err(&ptdev->base, "failed to unmap range %llx-%llx (requested range %llx-%llx)\n",
- iova + offset + unmapped_sz,
- iova + offset + pgsize * pgcount,
- iova, iova + size);
- panthor_vm_flush_range(vm, iova, offset + unmapped_sz);
- return -EINVAL;
+ /* If we don't make progress, we're screwed. That also means
+ * something else prevents us from unmapping the region, but
+ * there's not much we can do here: time for debugging.
+ */
+ if (drm_WARN_ON_ONCE(&ptdev->base, !unmapped_sz))
+ return;
}
drm_dbg(&ptdev->base,
@@ -929,8 +917,6 @@ static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
offset += unmapped_sz;
}
-
- return panthor_vm_flush_range(vm, iova, size);
}
static int
@@ -948,6 +934,10 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot,
if (!size)
return 0;
+ drm_WARN_ON(&ptdev->base,
+ (iova < vm->locked_region.start) ||
+ (iova + size > vm->locked_region.start + vm->locked_region.size));
+
for_each_sgtable_dma_sg(sgt, sgl, count) {
dma_addr_t paddr = sg_dma_address(sgl);
size_t len = sg_dma_len(sgl);
@@ -978,16 +968,17 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot,
paddr += mapped;
len -= mapped;
- if (drm_WARN_ON(&ptdev->base, !ret && !mapped))
+ /* If nothing was mapped, consider it an ENOMEM. */
+ if (!ret && !mapped)
ret = -ENOMEM;
- if (ret) {
- /* If something failed, unmap what we've already mapped before
- * returning. The unmap call is not supposed to fail.
+ /* If something fails, we stop there, and flag the VM unusable. */
+ if (drm_WARN_ON_ONCE(&ptdev->base, ret)) {
+ /* Unmap what we've already mapped to avoid leaving page
+ * table pages behind.
*/
- drm_WARN_ON(&ptdev->base,
- panthor_vm_unmap_pages(vm, start_iova,
- iova - start_iova));
+ panthor_vm_unmap_pages(vm, start_iova, iova - start_iova);
+ panthor_vm_declare_unusable(vm);
return ret;
}
}
@@ -998,7 +989,7 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot,
offset = 0;
}
- return panthor_vm_flush_range(vm, start_iova, iova - start_iova);
+ return 0;
}
static int flags_to_prot(u32 flags)
@@ -1641,6 +1632,62 @@ static const char *access_type_name(struct panthor_device *ptdev,
}
}
+static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size)
+{
+ struct panthor_device *ptdev = vm->ptdev;
+ int ret = 0;
+
+ mutex_lock(&ptdev->mmu->as.slots_lock);
+ drm_WARN_ON(&ptdev->base, vm->locked_region.start || vm->locked_region.size);
+ if (vm->as.id >= 0 && size) {
+ /* Lock the region that needs to be updated */
+ gpu_write64(ptdev, AS_LOCKADDR(vm->as.id),
+ pack_region_range(ptdev, start, size));
+
+ /* If the lock succeeded, update the locked_region info. */
+ ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_LOCK);
+ }
+
+ if (!ret) {
+ vm->locked_region.start = start;
+ vm->locked_region.size = size;
+ }
+ mutex_unlock(&ptdev->mmu->as.slots_lock);
+
+ return ret;
+}
+
+static void panthor_vm_unlock_region(struct panthor_vm *vm)
+{
+ struct panthor_device *ptdev = vm->ptdev;
+
+ mutex_lock(&ptdev->mmu->as.slots_lock);
+ if (vm->as.id >= 0) {
+ int ret;
+
+ /* flush+invalidate RW caches and invalidate RO ones.
+ * TODO: See if we can use FLUSH_PA_RANGE when the physical
+ * range is narrow enough and the HW supports it.
+ */
+ ret = panthor_gpu_flush_caches(ptdev, CACHE_CLEAN | CACHE_INV,
+ CACHE_CLEAN | CACHE_INV,
+ CACHE_INV);
+
+ /* Unlock the region if the flush is effective. */
+ if (!ret)
+ ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK);
+
+ /* If we fail to flush or unlock the region, schedule a GPU reset
+ * to unblock the situation.
+ */
+ if (ret)
+ panthor_device_schedule_reset(ptdev);
+ }
+ vm->locked_region.start = 0;
+ vm->locked_region.size = 0;
+ mutex_unlock(&ptdev->mmu->as.slots_lock);
+}
+
static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
{
bool has_unhandled_faults = false;
@@ -1701,7 +1748,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
ptdev->mmu->as.slots[as].vm->unhandled_fault = true;
/* Disable the MMU to kill jobs on this AS. */
- panthor_mmu_as_disable(ptdev, as);
+ panthor_mmu_as_disable(ptdev, as, false);
mutex_unlock(&ptdev->mmu->as.slots_lock);
status &= ~mask;
@@ -1730,7 +1777,8 @@ void panthor_mmu_suspend(struct panthor_device *ptdev)
struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm;
if (vm) {
- drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i));
+ drm_WARN_ON(&ptdev->base,
+ panthor_mmu_as_disable(ptdev, i, false));
panthor_vm_release_as_locked(vm);
}
}
@@ -1845,12 +1893,13 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm)
drm_sched_entity_destroy(&vm->entity);
drm_sched_fini(&vm->sched);
+ mutex_lock(&vm->op_lock);
mutex_lock(&ptdev->mmu->as.slots_lock);
if (vm->as.id >= 0) {
int cookie;
if (drm_dev_enter(&ptdev->base, &cookie)) {
- panthor_mmu_as_disable(ptdev, vm->as.id);
+ panthor_mmu_as_disable(ptdev, vm->as.id, false);
drm_dev_exit(cookie);
}
@@ -1859,6 +1908,7 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm)
list_del(&vm->as.lru_node);
}
mutex_unlock(&ptdev->mmu->as.slots_lock);
+ mutex_unlock(&vm->op_lock);
free_io_pgtable_ops(vm->pgtbl_ops);
@@ -2060,12 +2110,9 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
struct panthor_vm_op_ctx *op_ctx = vm->op_ctx;
struct panthor_vma *prev_vma = NULL, *next_vma = NULL;
u64 unmap_start, unmap_range;
- int ret;
drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range);
- ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range);
- if (ret)
- return ret;
+ panthor_vm_unmap_pages(vm, unmap_start, unmap_range);
if (op->remap.prev) {
prev_vma = panthor_vm_op_ctx_get_vma(op_ctx);
@@ -2103,13 +2150,9 @@ static int panthor_gpuva_sm_step_unmap(struct drm_gpuva_op *op,
{
struct panthor_vma *unmap_vma = container_of(op->unmap.va, struct panthor_vma, base);
struct panthor_vm *vm = priv;
- int ret;
-
- ret = panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr,
- unmap_vma->base.va.range);
- if (drm_WARN_ON(&vm->ptdev->base, ret))
- return ret;
+ panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr,
+ unmap_vma->base.va.range);
drm_gpuva_unmap(&op->unmap);
panthor_vma_unlink(unmap_vma);
return 0;
@@ -2154,6 +2197,11 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op,
mutex_lock(&vm->op_lock);
vm->op_ctx = op;
+
+ ret = panthor_vm_lock_region(vm, op->va.addr, op->va.range);
+ if (ret)
+ goto out;
+
switch (op_type) {
case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: {
const struct drm_gpuvm_map_req map_req = {
@@ -2181,8 +2229,11 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op,
break;
}
+ panthor_vm_unlock_region(vm);
+
+out:
if (ret && flag_vm_unusable_on_failure)
- vm->unusable = true;
+ panthor_vm_declare_unusable(vm);
vm->op_ctx = NULL;
mutex_unlock(&vm->op_lock);
@@ -2694,7 +2745,8 @@ void panthor_mmu_unplug(struct panthor_device *ptdev)
struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm;
if (vm) {
- drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i));
+ drm_WARN_ON(&ptdev->base,
+ panthor_mmu_as_disable(ptdev, i, false));
panthor_vm_release_as_locked(vm);
}
}
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index a6b8024e1a3c..0f83e778d89a 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/rcupdate.h>
#include "panthor_devfreq.h"
#include "panthor_device.h"
@@ -108,15 +109,6 @@ struct panthor_csg_slot {
/** @priority: Group priority. */
u8 priority;
-
- /**
- * @idle: True if the group bound to this slot is idle.
- *
- * A group is idle when it has nothing waiting for execution on
- * all its queues, or when queues are blocked waiting for something
- * to happen (synchronization object).
- */
- bool idle;
};
/**
@@ -878,8 +870,11 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue
struct iosys_map map;
int ret;
- if (queue->syncwait.kmap)
- return queue->syncwait.kmap + queue->syncwait.offset;
+ if (queue->syncwait.kmap) {
+ bo = container_of(queue->syncwait.obj,
+ struct panthor_gem_object, base.base);
+ goto out_sync;
+ }
bo = panthor_vm_get_bo_for_va(group->vm,
queue->syncwait.gpu_va,
@@ -896,6 +891,17 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue
if (drm_WARN_ON(&ptdev->base, !queue->syncwait.kmap))
goto err_put_syncwait_obj;
+out_sync:
+ /* Make sure the CPU caches are invalidated before the seqno is read.
+ * drm_gem_shmem_sync() is a NOP if map_wc=true, so no need to check
+ * it here.
+ */
+ panthor_gem_sync(&bo->base.base, queue->syncwait.offset,
+ queue->syncwait.sync64 ?
+ sizeof(struct panthor_syncobj_64b) :
+ sizeof(struct panthor_syncobj_32b),
+ DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE);
+
return queue->syncwait.kmap + queue->syncwait.offset;
err_put_syncwait_obj:
@@ -908,9 +914,8 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue *
if (IS_ERR_OR_NULL(queue))
return;
- /* This should have been disabled before that point. */
- drm_WARN_ON(&group->ptdev->base,
- disable_delayed_work_sync(&queue->timeout.work));
+ /* Disable the timeout before tearing down drm_sched components. */
+ disable_delayed_work_sync(&queue->timeout.work);
if (queue->entity.fence_context)
drm_sched_entity_destroy(&queue->entity);
@@ -939,6 +944,9 @@ static void group_release_work(struct work_struct *work)
release_work);
u32 i;
+ /* dma-fences may still be accessing group->queues under rcu lock. */
+ synchronize_rcu();
+
for (i = 0; i < group->queue_count; i++)
group_free_queue(group, group->queues[i]);
@@ -1062,28 +1070,11 @@ group_unbind_locked(struct panthor_group *group)
static bool
group_is_idle(struct panthor_group *group)
{
- struct panthor_device *ptdev = group->ptdev;
- u32 inactive_queues;
+ u32 inactive_queues = group->idle_queues | group->blocked_queues;
- if (group->csg_id >= 0)
- return ptdev->scheduler->csg_slots[group->csg_id].idle;
-
- inactive_queues = group->idle_queues | group->blocked_queues;
return hweight32(inactive_queues) == group->queue_count;
}
-static void
-queue_reset_timeout_locked(struct panthor_queue *queue)
-{
- lockdep_assert_held(&queue->fence_ctx.lock);
-
- if (queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT) {
- mod_delayed_work(queue->scheduler.timeout_wq,
- &queue->timeout.work,
- msecs_to_jiffies(JOB_TIMEOUT_MS));
- }
-}
-
static bool
group_can_run(struct panthor_group *group)
{
@@ -1101,6 +1092,18 @@ queue_timeout_is_suspended(struct panthor_queue *queue)
}
static void
+queue_reset_timeout_locked(struct panthor_queue *queue)
+{
+ lockdep_assert_held(&queue->fence_ctx.lock);
+
+ if (!queue_timeout_is_suspended(queue)) {
+ mod_delayed_work(queue->scheduler.timeout_wq,
+ &queue->timeout.work,
+ msecs_to_jiffies(JOB_TIMEOUT_MS));
+ }
+}
+
+static void
queue_suspend_timeout_locked(struct panthor_queue *queue)
{
unsigned long qtimeout, now;
@@ -1200,12 +1203,10 @@ cs_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id)
panthor_fw_update_reqs(cs_iface, req,
CS_IDLE_SYNC_WAIT |
CS_IDLE_EMPTY |
- CS_STATE_START |
- CS_EXTRACT_EVENT,
+ CS_STATE_START,
CS_IDLE_SYNC_WAIT |
CS_IDLE_EMPTY |
- CS_STATE_MASK |
- CS_EXTRACT_EVENT);
+ CS_STATE_MASK);
if (queue->iface.input->insert != queue->iface.input->extract)
queue_resume_timeout(queue);
}
@@ -1725,17 +1726,6 @@ static bool cs_slot_process_irq_locked(struct panthor_device *ptdev,
return (events & (CS_FAULT | CS_TILER_OOM)) != 0;
}
-static void csg_slot_sync_idle_state_locked(struct panthor_device *ptdev, u32 csg_id)
-{
- struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id];
- struct panthor_fw_csg_iface *csg_iface;
-
- lockdep_assert_held(&ptdev->scheduler->lock);
-
- csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id);
- csg_slot->idle = csg_iface->output->status_state & CSG_STATUS_STATE_IS_IDLE;
-}
-
static void csg_slot_process_idle_event_locked(struct panthor_device *ptdev, u32 csg_id)
{
struct panthor_scheduler *sched = ptdev->scheduler;
@@ -1997,10 +1987,8 @@ static int csgs_upd_ctx_apply_locked(struct panthor_device *ptdev,
if (acked & CSG_STATE_MASK)
csg_slot_sync_state_locked(ptdev, csg_id);
- if (acked & CSG_STATUS_UPDATE) {
+ if (acked & CSG_STATUS_UPDATE)
csg_slot_sync_queues_state_locked(ptdev, csg_id);
- csg_slot_sync_idle_state_locked(ptdev, csg_id);
- }
if (ret && acked != req_mask &&
((csg_iface->input->req ^ csg_iface->output->ack) & req_mask) != 0) {
@@ -2020,10 +2008,10 @@ struct panthor_sched_tick_ctx {
struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT];
u32 idle_group_count;
u32 group_count;
- enum panthor_csg_priority min_priority;
struct panthor_vm *vms[MAX_CS_PER_CSG];
u32 as_count;
bool immediate_tick;
+ bool stop_tick;
u32 csg_upd_failed_mask;
};
@@ -2066,17 +2054,21 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched,
if (!owned_by_tick_ctx)
group_get(group);
- list_move_tail(&group->run_node, &ctx->groups[group->priority]);
ctx->group_count++;
+
+ /* If we have more than one active group with the same priority,
+ * we need to keep ticking to rotate the CSG priority.
+ */
if (group_is_idle(group))
ctx->idle_group_count++;
+ else if (!list_empty(&ctx->groups[group->priority]))
+ ctx->stop_tick = false;
+
+ list_move_tail(&group->run_node, &ctx->groups[group->priority]);
if (i == ctx->as_count)
ctx->vms[ctx->as_count++] = group->vm;
- if (ctx->min_priority > group->priority)
- ctx->min_priority = group->priority;
-
if (tick_ctx_is_full(sched, ctx))
return;
}
@@ -2085,31 +2077,22 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched,
static void
tick_ctx_insert_old_group(struct panthor_scheduler *sched,
struct panthor_sched_tick_ctx *ctx,
- struct panthor_group *group,
- bool full_tick)
+ struct panthor_group *group)
{
struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id];
struct panthor_group *other_group;
- if (!full_tick) {
- list_add_tail(&group->run_node, &ctx->old_groups[group->priority]);
- return;
- }
-
- /* Rotate to make sure groups with lower CSG slot
- * priorities have a chance to get a higher CSG slot
- * priority next time they get picked. This priority
- * has an impact on resource request ordering, so it's
- * important to make sure we don't let one group starve
- * all other groups with the same group priority.
- */
+ /* Class groups in descending priority order so we can easily rotate. */
list_for_each_entry(other_group,
&ctx->old_groups[csg_slot->group->priority],
run_node) {
struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id];
- if (other_csg_slot->priority > csg_slot->priority) {
- list_add_tail(&csg_slot->group->run_node, &other_group->run_node);
+ /* Our group has a higher prio than the one we're testing against,
+ * place it just before.
+ */
+ if (csg_slot->priority > other_csg_slot->priority) {
+ list_add_tail(&group->run_node, &other_group->run_node);
return;
}
}
@@ -2119,8 +2102,7 @@ tick_ctx_insert_old_group(struct panthor_scheduler *sched,
static void
tick_ctx_init(struct panthor_scheduler *sched,
- struct panthor_sched_tick_ctx *ctx,
- bool full_tick)
+ struct panthor_sched_tick_ctx *ctx)
{
struct panthor_device *ptdev = sched->ptdev;
struct panthor_csg_slots_upd_ctx upd_ctx;
@@ -2130,7 +2112,7 @@ tick_ctx_init(struct panthor_scheduler *sched,
memset(ctx, 0, sizeof(*ctx));
csgs_upd_ctx_init(&upd_ctx);
- ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT;
+ ctx->stop_tick = true;
for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) {
INIT_LIST_HEAD(&ctx->groups[i]);
INIT_LIST_HEAD(&ctx->old_groups[i]);
@@ -2158,7 +2140,7 @@ tick_ctx_init(struct panthor_scheduler *sched,
group->fatal_queues |= GENMASK(group->queue_count - 1, 0);
}
- tick_ctx_insert_old_group(sched, ctx, group, full_tick);
+ tick_ctx_insert_old_group(sched, ctx, group);
csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i,
csg_iface->output->ack ^ CSG_STATUS_UPDATE,
CSG_STATUS_UPDATE);
@@ -2442,32 +2424,18 @@ static u64
tick_ctx_update_resched_target(struct panthor_scheduler *sched,
const struct panthor_sched_tick_ctx *ctx)
{
- /* We had space left, no need to reschedule until some external event happens. */
- if (!tick_ctx_is_full(sched, ctx))
- goto no_tick;
-
- /* If idle groups were scheduled, no need to wake up until some external
- * event happens (group unblocked, new job submitted, ...).
- */
- if (ctx->idle_group_count)
- goto no_tick;
+ u64 resched_target;
- if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT))
+ if (ctx->stop_tick)
goto no_tick;
- /* If there are groups of the same priority waiting, we need to
- * keep the scheduler ticking, otherwise, we'll just wait for
- * new groups with higher priority to be queued.
- */
- if (!list_empty(&sched->groups.runnable[ctx->min_priority])) {
- u64 resched_target = sched->last_tick + sched->tick_period;
+ resched_target = sched->last_tick + sched->tick_period;
- if (time_before64(sched->resched_target, sched->last_tick) ||
- time_before64(resched_target, sched->resched_target))
- sched->resched_target = resched_target;
+ if (time_before64(sched->resched_target, sched->last_tick) ||
+ time_before64(resched_target, sched->resched_target))
+ sched->resched_target = resched_target;
- return sched->resched_target - sched->last_tick;
- }
+ return sched->resched_target - sched->last_tick;
no_tick:
sched->resched_target = U64_MAX;
@@ -2480,9 +2448,11 @@ static void tick_work(struct work_struct *work)
tick_work.work);
struct panthor_device *ptdev = sched->ptdev;
struct panthor_sched_tick_ctx ctx;
+ u64 resched_target = sched->resched_target;
u64 remaining_jiffies = 0, resched_delay;
u64 now = get_jiffies_64();
int prio, ret, cookie;
+ bool full_tick;
if (!drm_dev_enter(&ptdev->base, &cookie))
return;
@@ -2491,18 +2461,24 @@ static void tick_work(struct work_struct *work)
if (drm_WARN_ON(&ptdev->base, ret))
goto out_dev_exit;
- if (time_before64(now, sched->resched_target))
- remaining_jiffies = sched->resched_target - now;
+ /* If the tick is stopped, calculate when the next tick would be */
+ if (resched_target == U64_MAX)
+ resched_target = sched->last_tick + sched->tick_period;
+
+ if (time_before64(now, resched_target))
+ remaining_jiffies = resched_target - now;
+
+ full_tick = remaining_jiffies == 0;
mutex_lock(&sched->lock);
if (panthor_device_reset_is_pending(sched->ptdev))
goto out_unlock;
- tick_ctx_init(sched, &ctx, remaining_jiffies != 0);
+ tick_ctx_init(sched, &ctx);
if (ctx.csg_upd_failed_mask)
goto out_cleanup_ctx;
- if (remaining_jiffies) {
+ if (!full_tick) {
/* Scheduling forced in the middle of a tick. Only RT groups
* can preempt non-RT ones. Currently running RT groups can't be
* preempted.
@@ -2524,9 +2500,29 @@ static void tick_work(struct work_struct *work)
for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1;
prio >= 0 && !tick_ctx_is_full(sched, &ctx);
prio--) {
+ struct panthor_group *old_highest_prio_group =
+ list_first_entry_or_null(&ctx.old_groups[prio],
+ struct panthor_group, run_node);
+
+ /* Pull out the group with the highest prio for rotation. */
+ if (old_highest_prio_group)
+ list_del(&old_highest_prio_group->run_node);
+
+ /* Re-insert old active groups so they get a chance to run with higher prio. */
+ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true);
+
+ /* Fill the remaining slots with runnable groups. */
tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio],
true, false);
- tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true);
+
+ /* Re-insert the old group with the highest prio, and give it a chance to be
+ * scheduled again (but with a lower prio) if there's room left.
+ */
+ if (old_highest_prio_group) {
+ list_add_tail(&old_highest_prio_group->run_node, &ctx.old_groups[prio]);
+ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio],
+ true, true);
+ }
}
/* If we have free CSG slots left, pick idle groups */
@@ -2651,14 +2647,33 @@ static void sync_upd_work(struct work_struct *work)
sched_queue_delayed_work(sched, tick, 0);
}
+static void sched_resume_tick(struct panthor_device *ptdev)
+{
+ struct panthor_scheduler *sched = ptdev->scheduler;
+ u64 delay_jiffies, now;
+
+ drm_WARN_ON(&ptdev->base, sched->resched_target != U64_MAX);
+
+ /* Scheduler tick was off, recalculate the resched_target based on the
+ * last tick event, and queue the scheduler work.
+ */
+ now = get_jiffies_64();
+ sched->resched_target = sched->last_tick + sched->tick_period;
+ if (sched->used_csg_slot_count == sched->csg_slot_count &&
+ time_before64(now, sched->resched_target))
+ delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX);
+ else
+ delay_jiffies = 0;
+
+ sched_queue_delayed_work(sched, tick, delay_jiffies);
+}
+
static void group_schedule_locked(struct panthor_group *group, u32 queue_mask)
{
struct panthor_device *ptdev = group->ptdev;
struct panthor_scheduler *sched = ptdev->scheduler;
struct list_head *queue = &sched->groups.runnable[group->priority];
- u64 delay_jiffies = 0;
bool was_idle;
- u64 now;
if (!group_can_run(group))
return;
@@ -2703,13 +2718,7 @@ static void group_schedule_locked(struct panthor_group *group, u32 queue_mask)
/* Scheduler tick was off, recalculate the resched_target based on the
* last tick event, and queue the scheduler work.
*/
- now = get_jiffies_64();
- sched->resched_target = sched->last_tick + sched->tick_period;
- if (sched->used_csg_slot_count == sched->csg_slot_count &&
- time_before64(now, sched->resched_target))
- delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX);
-
- sched_queue_delayed_work(sched, tick, delay_jiffies);
+ sched_resume_tick(ptdev);
}
static void queue_stop(struct panthor_queue *queue,
@@ -2767,13 +2776,6 @@ static void panthor_group_start(struct panthor_group *group)
group_put(group);
}
-static void panthor_sched_immediate_tick(struct panthor_device *ptdev)
-{
- struct panthor_scheduler *sched = ptdev->scheduler;
-
- sched_queue_delayed_work(sched, tick, 0);
-}
-
/**
* panthor_sched_report_mmu_fault() - Report MMU faults to the scheduler.
*/
@@ -2781,13 +2783,13 @@ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev)
{
/* Force a tick to immediately kill faulty groups. */
if (ptdev->scheduler)
- panthor_sched_immediate_tick(ptdev);
+ sched_queue_delayed_work(ptdev->scheduler, tick, 0);
}
void panthor_sched_resume(struct panthor_device *ptdev)
{
/* Force a tick to re-evaluate after a resume. */
- panthor_sched_immediate_tick(ptdev);
+ sched_queue_delayed_work(ptdev->scheduler, tick, 0);
}
void panthor_sched_suspend(struct panthor_device *ptdev)
@@ -2943,8 +2945,6 @@ void panthor_sched_pre_reset(struct panthor_device *ptdev)
* new jobs while we're resetting.
*/
for (i = 0; i < ARRAY_SIZE(sched->groups.runnable); i++) {
- /* All groups should be in the idle lists. */
- drm_WARN_ON(&ptdev->base, !list_empty(&sched->groups.runnable[i]));
list_for_each_entry_safe(group, group_tmp, &sched->groups.runnable[i], run_node)
panthor_group_stop(group);
}
@@ -3343,6 +3343,18 @@ queue_run_job(struct drm_sched_job *sched_job)
if (group->csg_id < 0) {
group_schedule_locked(group, BIT(job->queue_idx));
} else {
+ u32 queue_mask = BIT(job->queue_idx);
+ bool resume_tick = group_is_idle(group) &&
+ (group->idle_queues & queue_mask) &&
+ !(group->blocked_queues & queue_mask) &&
+ sched->resched_target == U64_MAX;
+
+ /* We just added something to the queue, so it's no longer idle. */
+ group->idle_queues &= ~queue_mask;
+
+ if (resume_tick)
+ sched_resume_tick(ptdev);
+
gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1);
if (!sched->pm.has_ref &&
!(group->blocked_queues & BIT(job->queue_idx))) {
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c
index 3a9661b9b1fc..5d10bc5fdf1f 100644
--- a/drivers/gpu/drm/pl111/pl111_display.c
+++ b/drivers/gpu/drm/pl111/pl111_display.c
@@ -138,7 +138,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
ret = clk_set_rate(priv->clk, mode->clock * 1000);
if (ret) {
- dev_err(drm->dev,
+ drm_err(drm,
"Failed to set pixel clock rate to %d: %d\n",
mode->clock * 1000, ret);
}
@@ -553,7 +553,7 @@ pl111_init_clock_divider(struct drm_device *drm)
int ret;
if (IS_ERR(parent)) {
- dev_err(drm->dev, "CLCD: unable to get clcdclk.\n");
+ drm_err(drm, "CLCD: unable to get clcdclk.\n");
return PTR_ERR(parent);
}
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index 56ff6a3fb483..ac9e4b6bd2eb 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -55,6 +55,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -98,7 +99,7 @@ static int pl111_modeset_init(struct drm_device *dev)
struct drm_panel *tmp_panel;
struct drm_bridge *tmp_bridge;
- dev_dbg(dev->dev, "checking endpoint %d\n", i);
+ drm_dbg(dev, "checking endpoint %d\n", i);
ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
0, i,
@@ -114,18 +115,18 @@ static int pl111_modeset_init(struct drm_device *dev)
defer = true;
} else if (ret != -ENODEV) {
/* Continue, maybe something else is working */
- dev_err(dev->dev,
+ drm_err(dev,
"endpoint %d returns %d\n", i, ret);
}
}
if (tmp_panel) {
- dev_info(dev->dev,
+ drm_info(dev,
"found panel on endpoint %d\n", i);
panel = tmp_panel;
}
if (tmp_bridge) {
- dev_info(dev->dev,
+ drm_info(dev,
"found bridge on endpoint %d\n", i);
bridge = tmp_bridge;
}
@@ -149,9 +150,9 @@ static int pl111_modeset_init(struct drm_device *dev)
goto finish;
}
} else if (bridge) {
- dev_info(dev->dev, "Using non-panel bridge\n");
+ drm_info(dev, "Using non-panel bridge\n");
} else {
- dev_err(dev->dev, "No bridge, exiting\n");
+ drm_err(dev, "No bridge, exiting\n");
return -ENODEV;
}
@@ -163,7 +164,7 @@ static int pl111_modeset_init(struct drm_device *dev)
ret = pl111_display_init(dev);
if (ret != 0) {
- dev_err(dev->dev, "Failed to init display\n");
+ drm_err(dev, "Failed to init display\n");
goto out_bridge;
}
@@ -175,7 +176,7 @@ static int pl111_modeset_init(struct drm_device *dev)
if (!priv->variant->broken_vblank) {
ret = drm_vblank_init(dev, 1);
if (ret != 0) {
- dev_err(dev->dev, "Failed to init vblank\n");
+ drm_err(dev, "Failed to init vblank\n");
goto out_bridge;
}
}
@@ -255,13 +256,13 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
ret = of_reserved_mem_device_init(dev);
if (!ret) {
- dev_info(dev, "using device-specific reserved memory\n");
+ drm_info(drm, "using device-specific reserved memory\n");
priv->use_device_memory = true;
}
if (of_property_read_u32(dev->of_node, "max-memory-bandwidth",
&priv->memory_bw)) {
- dev_info(dev, "no max memory bandwidth specified, assume unlimited\n");
+ drm_info(drm, "no max memory bandwidth specified, assume unlimited\n");
priv->memory_bw = 0;
}
@@ -276,17 +277,17 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
priv->regs = devm_ioremap_resource(dev, &amba_dev->res);
if (IS_ERR(priv->regs)) {
- dev_err(dev, "%s failed mmio\n", __func__);
+ drm_err(drm, "%s failed mmio\n", __func__);
ret = PTR_ERR(priv->regs);
goto dev_put;
}
/* This may override some variant settings */
- ret = pl111_versatile_init(dev, priv);
+ ret = pl111_versatile_init(drm, priv);
if (ret)
goto dev_put;
- pl111_nomadik_init(dev);
+ pl111_nomadik_init(drm);
/* turn off interrupts before requesting the irq */
writel(0, priv->regs + priv->ienb);
@@ -294,7 +295,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0,
variant->name, priv);
if (ret != 0) {
- dev_err(dev, "%s failed irq %d\n", __func__, ret);
+ drm_err(drm, "%s failed irq %d\n", __func__, ret);
return ret;
}
diff --git a/drivers/gpu/drm/pl111/pl111_nomadik.c b/drivers/gpu/drm/pl111/pl111_nomadik.c
index 6f385e59be22..f3218d59c5f1 100644
--- a/drivers/gpu/drm/pl111/pl111_nomadik.c
+++ b/drivers/gpu/drm/pl111/pl111_nomadik.c
@@ -9,7 +9,7 @@
#define PMU_CTRL_OFFSET 0x0000
#define PMU_CTRL_LCDNDIF BIT(26)
-void pl111_nomadik_init(struct device *dev)
+void pl111_nomadik_init(struct drm_device *dev)
{
struct regmap *pmu_regmap;
@@ -31,6 +31,6 @@ void pl111_nomadik_init(struct device *dev)
PMU_CTRL_OFFSET,
PMU_CTRL_LCDNDIF,
0);
- dev_info(dev, "set Nomadik PMU mux to CLCD mode\n");
+ drm_info(dev, "set Nomadik PMU mux to CLCD mode\n");
}
EXPORT_SYMBOL_GPL(pl111_nomadik_init);
diff --git a/drivers/gpu/drm/pl111/pl111_nomadik.h b/drivers/gpu/drm/pl111/pl111_nomadik.h
index 47ccf5c839fc..b2c9f7cc1c8c 100644
--- a/drivers/gpu/drm/pl111/pl111_nomadik.h
+++ b/drivers/gpu/drm/pl111/pl111_nomadik.h
@@ -8,11 +8,11 @@ struct device;
#ifdef CONFIG_ARCH_NOMADIK
-void pl111_nomadik_init(struct device *dev);
+void pl111_nomadik_init(struct drm_device *dev);
#else
-static inline void pl111_nomadik_init(struct device *dev)
+static inline void pl111_nomadik_init(struct drm_device *dev)
{
}
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c
index 5f460b296c0c..0d8331a3909f 100644
--- a/drivers/gpu/drm/pl111/pl111_versatile.c
+++ b/drivers/gpu/drm/pl111/pl111_versatile.c
@@ -20,6 +20,7 @@
#include <linux/vexpress.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
#include "pl111_versatile.h"
#include "pl111_drm.h"
@@ -116,7 +117,7 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format)
{
u32 val;
- dev_info(drm->dev, "enable Integrator CLCD connectors\n");
+ drm_info(drm, "enable Integrator CLCD connectors\n");
/* FIXME: really needed? */
val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
@@ -134,7 +135,7 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format)
val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
break;
default:
- dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n",
+ drm_err(drm, "unhandled format on Integrator 0x%08x\n",
format);
break;
}
@@ -156,7 +157,7 @@ static void pl111_impd1_enable(struct drm_device *drm, u32 format)
{
u32 val;
- dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n");
+ drm_info(drm, "enable IM-PD1 CLCD connectors\n");
val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE;
regmap_update_bits(versatile_syscon_map,
@@ -167,7 +168,7 @@ static void pl111_impd1_enable(struct drm_device *drm, u32 format)
static void pl111_impd1_disable(struct drm_device *drm)
{
- dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n");
+ drm_info(drm, "disable IM-PD1 CLCD connectors\n");
regmap_update_bits(versatile_syscon_map,
IMPD1_CTRL_OFFSET,
@@ -194,7 +195,7 @@ static void pl111_impd1_disable(struct drm_device *drm)
static void pl111_versatile_disable(struct drm_device *drm)
{
- dev_info(drm->dev, "disable Versatile CLCD connectors\n");
+ drm_info(drm, "disable Versatile CLCD connectors\n");
regmap_update_bits(versatile_syscon_map,
SYS_CLCD,
SYS_CLCD_CONNECTOR_MASK,
@@ -205,7 +206,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format)
{
u32 val = 0;
- dev_info(drm->dev, "enable Versatile CLCD connectors\n");
+ drm_info(drm, "enable Versatile CLCD connectors\n");
switch (format) {
case DRM_FORMAT_ABGR8888:
@@ -227,7 +228,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format)
val |= SYS_CLCD_MODE_5551;
break;
default:
- dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n",
+ drm_err(drm, "unhandled format on Versatile 0x%08x\n",
format);
break;
}
@@ -247,7 +248,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format)
static void pl111_realview_clcd_disable(struct drm_device *drm)
{
- dev_info(drm->dev, "disable RealView CLCD connectors\n");
+ drm_info(drm, "disable RealView CLCD connectors\n");
regmap_update_bits(versatile_syscon_map,
SYS_CLCD,
SYS_CLCD_CONNECTOR_MASK,
@@ -256,7 +257,7 @@ static void pl111_realview_clcd_disable(struct drm_device *drm)
static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)
{
- dev_info(drm->dev, "enable RealView CLCD connectors\n");
+ drm_info(drm, "enable RealView CLCD connectors\n");
regmap_update_bits(versatile_syscon_map,
SYS_CLCD,
SYS_CLCD_CONNECTOR_MASK,
@@ -376,7 +377,7 @@ static const struct pl111_variant_data pl111_vexpress = {
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02
-static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,
+static int pl111_vexpress_clcd_init(struct drm_device *dev, struct device_node *np,
struct pl111_drm_dev_private *priv)
{
struct platform_device *pdev;
@@ -433,22 +434,22 @@ static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,
mux_motherboard = false;
if (mux_motherboard) {
- dev_info(dev, "DVI muxed to motherboard CLCD\n");
+ drm_info(dev, "DVI muxed to motherboard CLCD\n");
val = VEXPRESS_FPGAMUX_MOTHERBOARD;
- } else if (ct_clcd == dev->of_node) {
- dev_info(dev,
+ } else if (ct_clcd == dev->dev->of_node) {
+ drm_info(dev,
"DVI muxed to daughterboard 1 (core tile) CLCD\n");
val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1;
} else {
- dev_info(dev, "core tile graphics present\n");
- dev_info(dev, "this device will be deactivated\n");
+ drm_info(dev, "core tile graphics present\n");
+ drm_info(dev, "this device will be deactivated\n");
return -ENODEV;
}
/* Call into deep Vexpress configuration API */
pdev = of_find_device_by_node(np);
if (!pdev) {
- dev_err(dev, "can't find the sysreg device, deferring\n");
+ drm_err(dev, "can't find the sysreg device, deferring\n");
return -EPROBE_DEFER;
}
@@ -461,17 +462,17 @@ static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,
ret = regmap_write(map, 0, val);
platform_device_put(pdev);
if (ret) {
- dev_err(dev, "error setting DVI muxmode\n");
+ drm_err(dev, "error setting DVI muxmode\n");
return -ENODEV;
}
priv->variant = &pl111_vexpress;
- dev_info(dev, "initializing Versatile Express PL111\n");
+ drm_info(dev, "initializing Versatile Express PL111\n");
return 0;
}
-int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
+int pl111_versatile_init(struct drm_device *dev, struct pl111_drm_dev_private *priv)
{
const struct of_device_id *clcd_id;
enum versatile_clcd versatile_clcd_type;
@@ -492,7 +493,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
int ret = pl111_vexpress_clcd_init(dev, np, priv);
of_node_put(np);
if (ret)
- dev_err(dev, "Versatile Express init failed - %d", ret);
+ drm_err(dev, "Versatile Express init failed - %d", ret);
return ret;
}
@@ -511,7 +512,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
map = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(map)) {
- dev_err(dev, "no Versatile syscon regmap\n");
+ drm_err(dev, "no Versatile syscon regmap\n");
return PTR_ERR(map);
}
@@ -520,14 +521,14 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
versatile_syscon_map = map;
priv->variant = &pl110_integrator;
priv->variant_display_enable = pl111_integrator_enable;
- dev_info(dev, "set up callbacks for Integrator PL110\n");
+ drm_info(dev, "set up callbacks for Integrator PL110\n");
break;
case INTEGRATOR_IMPD1:
versatile_syscon_map = map;
priv->variant = &pl110_impd1;
priv->variant_display_enable = pl111_impd1_enable;
priv->variant_display_disable = pl111_impd1_disable;
- dev_info(dev, "set up callbacks for IM-PD1 PL110\n");
+ drm_info(dev, "set up callbacks for IM-PD1 PL110\n");
break;
case VERSATILE_CLCD:
versatile_syscon_map = map;
@@ -542,7 +543,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
*/
priv->ienb = CLCD_PL111_IENB;
priv->ctrl = CLCD_PL111_CNTL;
- dev_info(dev, "set up callbacks for Versatile PL110\n");
+ drm_info(dev, "set up callbacks for Versatile PL110\n");
break;
case REALVIEW_CLCD_EB:
case REALVIEW_CLCD_PB1176:
@@ -553,10 +554,10 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
priv->variant = &pl111_realview;
priv->variant_display_enable = pl111_realview_clcd_enable;
priv->variant_display_disable = pl111_realview_clcd_disable;
- dev_info(dev, "set up callbacks for RealView PL111\n");
+ drm_info(dev, "set up callbacks for RealView PL111\n");
break;
default:
- dev_info(dev, "unknown Versatile system controller\n");
+ drm_info(dev, "unknown Versatile system controller\n");
break;
}
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.h b/drivers/gpu/drm/pl111/pl111_versatile.h
index 143877010042..7a15c5f7efe8 100644
--- a/drivers/gpu/drm/pl111/pl111_versatile.h
+++ b/drivers/gpu/drm/pl111/pl111_versatile.h
@@ -7,6 +7,6 @@
struct device;
struct pl111_drm_dev_private;
-int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv);
+int pl111_versatile_init(struct drm_device *dev, struct pl111_drm_dev_private *priv);
#endif
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 9b3a3a9d60e2..2fc0334e0d6c 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1133,7 +1133,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1150,33 +1150,23 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
bool bypass_lut = false;
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
- /* If atomic, assume fb object is pinned & idle & fenced and
- * just update base pointers
- */
obj = target_fb->obj[0];
rbo = gem_to_radeon_bo(obj);
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
return r;
- if (atomic)
- fb_location = radeon_bo_gpu_offset(rbo);
- else {
- r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
- if (unlikely(r != 0)) {
- radeon_bo_unreserve(rbo);
- return -EINVAL;
- }
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ return -EINVAL;
}
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
@@ -1437,7 +1427,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
/* set pageflip to happen anywhere in vblank interval */
WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
rbo = gem_to_radeon_bo(fb->obj[0]);
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -1454,7 +1444,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1470,15 +1460,12 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
bool bypass_lut = false;
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
obj = target_fb->obj[0];
rbo = gem_to_radeon_bo(obj);
@@ -1486,17 +1473,10 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
if (unlikely(r != 0))
return r;
- /* If atomic, assume fb object is pinned & idle & fenced and
- * just update base pointers
- */
- if (atomic)
- fb_location = radeon_bo_gpu_offset(rbo);
- else {
- r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
- if (unlikely(r != 0)) {
- radeon_bo_unreserve(rbo);
- return -EINVAL;
- }
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ return -EINVAL;
}
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
radeon_bo_unreserve(rbo);
@@ -1645,7 +1625,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
/* set pageflip to happen only at start of vblank interval (front porch) */
WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
rbo = gem_to_radeon_bo(fb->obj[0]);
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -1667,26 +1647,11 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct radeon_device *rdev = dev->dev_private;
if (ASIC_IS_DCE4(rdev))
- return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0);
- else if (ASIC_IS_AVIVO(rdev))
- return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
- else
- return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- struct drm_device *dev = crtc->dev;
- struct radeon_device *rdev = dev->dev_private;
-
- if (ASIC_IS_DCE4(rdev))
- return dce4_crtc_do_set_base(crtc, fb, x, y, 1);
+ return dce4_crtc_do_set_base(crtc, old_fb, x, y);
else if (ASIC_IS_AVIVO(rdev))
- return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
+ return avivo_crtc_do_set_base(crtc, old_fb, x, y);
else
- return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
+ return radeon_crtc_do_set_base(crtc, old_fb, x, y);
}
/* properly set additional regs when using atombios */
@@ -2215,7 +2180,6 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.mode_fixup = atombios_crtc_mode_fixup,
.mode_set = atombios_crtc_mode_set,
.mode_set_base = atombios_crtc_set_base,
- .mode_set_base_atomic = atombios_crtc_set_base_atomic,
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
.disable = atombios_crtc_disable,
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 825b351ff53c..a1054c8094d4 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -360,19 +360,12 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
- return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, enum mode_set_atomic state)
-{
- return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
+ return radeon_crtc_do_set_base(crtc, old_fb, x, y);
}
int radeon_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic)
+ int x, int y)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -390,15 +383,12 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
DRM_DEBUG_KMS("\n");
/* no fb bound */
- if (!atomic && !crtc->primary->fb) {
+ if (!crtc->primary->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- if (atomic)
- target_fb = fb;
- else
- target_fb = crtc->primary->fb;
+ target_fb = crtc->primary->fb;
switch (target_fb->format->cpp[0] * 8) {
case 8:
@@ -445,7 +435,7 @@ retry:
* We don't shutdown the display controller because new buffer
* will end up in same spot.
*/
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
struct radeon_bo *old_rbo;
unsigned long nsize, osize;
@@ -555,7 +545,7 @@ retry:
WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
- if (!atomic && fb && fb != crtc->primary->fb) {
+ if (fb && fb != crtc->primary->fb) {
rbo = gem_to_radeon_bo(fb->obj[0]);
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -1108,7 +1098,6 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
.mode_fixup = radeon_crtc_mode_fixup,
.mode_set = radeon_crtc_mode_set,
.mode_set_base = radeon_crtc_set_base,
- .mode_set_base_atomic = radeon_crtc_set_base_atomic,
.prepare = radeon_crtc_prepare,
.commit = radeon_crtc_commit,
.disable = radeon_crtc_disable,
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 9e34da2cacef..088af85902f7 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -804,10 +804,6 @@ extern bool radeon_encoder_is_digital(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
-extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y,
- enum mode_set_atomic state);
extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -817,13 +813,9 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
-extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y,
- enum mode_set_atomic state);
extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
- int x, int y, int atomic);
+ int x, int y);
extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 3b52dfc0ea1e..5edd45424562 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
@@ -32,6 +33,8 @@
#include "rzg2l_mipi_dsi_regs.h"
+MODULE_IMPORT_NS("RZV2H_CPG");
+
#define RZG2L_DCS_BUF_SIZE 128 /* Maximum DCS buffer size in external memory. */
#define RZ_MIPI_DSI_FEATURE_16BPP BIT(0)
@@ -46,6 +49,11 @@ struct rzg2l_mipi_dsi_hw_info {
u64 *hsfreq_millihz);
unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
unsigned long mode_freq);
+ struct {
+ const struct rzv2h_pll_limits **limits;
+ const u8 *table;
+ const u8 table_size;
+ } cpg_plldsi;
u32 phy_reg_offset;
u32 link_reg_offset;
unsigned long min_dclk;
@@ -53,6 +61,11 @@ struct rzg2l_mipi_dsi_hw_info {
u8 features;
};
+struct rzv2h_dsi_mode_calc {
+ unsigned long mode_freq_khz;
+ struct rzv2h_pll_pars dsi_parameters;
+};
+
struct rzg2l_mipi_dsi {
struct device *dev;
void __iomem *mmio;
@@ -68,17 +81,29 @@ struct rzg2l_mipi_dsi {
struct drm_bridge *next_bridge;
struct clk *vclk;
+ struct clk *lpclk;
enum mipi_dsi_pixel_format format;
unsigned int num_data_lanes;
unsigned int lanes;
unsigned long mode_flags;
+ struct rzv2h_dsi_mode_calc mode_calc;
+
/* DCS buffer pointers when using external memory. */
dma_addr_t dcs_buf_phys;
u8 *dcs_buf_virt;
};
+static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
+ .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
+ .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
+ .m = { .min = 64, .max = 1023 },
+ .p = { .min = 1, .max = 4 },
+ .s = { .min = 0, .max = 5 },
+ .k = { .min = -32768, .max = 32767 },
+};
+
static inline struct rzg2l_mipi_dsi *
bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
{
@@ -193,6 +218,237 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
},
};
+/**
+ * struct rzv2h_mipi_dsi_timings - Timing parameter table structure
+ *
+ * @hsfreq: Pointer to frequency threshold array
+ * @len: Number of entries in the hsfreq array
+ * @base_value: Base register value offset for this timing parameter
+ *
+ * Each timing parameter (TCLK*, THS*, etc.) has its own table with
+ * frequency thresholds and corresponding base register values.
+ */
+struct rzv2h_mipi_dsi_timings {
+ const u8 *hsfreq;
+ u8 len;
+ u8 base_value;
+};
+
+/*
+ * enum rzv2h_dsi_timing_idx - MIPI DSI timing parameter indices
+ *
+ * These enums correspond to different MIPI DSI PHY timing parameters.
+ */
+enum rzv2h_dsi_timing_idx {
+ TCLKPRPRCTL,
+ TCLKZEROCTL,
+ TCLKPOSTCTL,
+ TCLKTRAILCTL,
+ THSPRPRCTL,
+ THSZEROCTL,
+ THSTRAILCTL,
+ TLPXCTL,
+ THSEXITCTL,
+};
+
+/*
+ * RZ/V2H(P) Frequency threshold lookup tables for D-PHY timing parameters
+ *
+ * - Each array contains frequency thresholds (in units of 10 Mbps),
+ * taken directly from the table 9.5-4 hardware manual.
+ * - These thresholds define the frequency ranges for which timing
+ * register values must be programmed.
+ * - The actual register value is calculated in
+ * rzv2h_dphy_find_timings_val():
+ *
+ * register_value = timings->base_value + table_index
+ *
+ * Example (TCLKPRPRCTL, from HW manual):
+ * 0-150 Mbps -> index 0 -> register_value = base + 0 = 0 + 0 = 0
+ * 151-260 Mbps -> index 1 -> register_value = base + 1 = 0 + 1 = 1
+ * 261-370 Mbps -> index 2 -> register_value = base + 2 = 0 + 2 = 2
+ *
+ * Each of the following arrays corresponds to a specific timing
+ * parameter (TCLKPRPRCTL, TCLKZEROCTL, TCLKPOSTCTL, etc.).
+ */
+static const u8 tclkprprctl[] = {
+ 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150,
+};
+
+static const u8 tclkzeroctl[] = {
+ 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
+ 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
+ 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
+ 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
+ 134, 137, 139, 141, 143, 146, 148, 150,
+};
+
+static const u8 tclkpostctl[] = {
+ 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150,
+};
+
+static const u8 tclktrailctl[] = {
+ 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150,
+};
+
+static const u8 thsprprctl[] = {
+ 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150,
+};
+
+static const u8 thszeroctl[] = {
+ 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
+ 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150,
+};
+
+static const u8 thstrailctl[] = {
+ 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150,
+};
+
+static const u8 tlpxctl[] = {
+ 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
+};
+
+static const u8 thsexitctl[] = {
+ 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
+ 95, 103, 111, 119, 127, 135, 143, 150,
+};
+
+/*
+ * rzv2h_dsi_timings_tables - main timing parameter lookup table
+ * Maps timing parameter enum to its frequency table, array length and
+ * base register offset value.
+ */
+static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
+ [TCLKPRPRCTL] = {
+ .hsfreq = tclkprprctl,
+ .len = ARRAY_SIZE(tclkprprctl),
+ .base_value = 0,
+ },
+ [TCLKZEROCTL] = {
+ .hsfreq = tclkzeroctl,
+ .len = ARRAY_SIZE(tclkzeroctl),
+ .base_value = 2,
+ },
+ [TCLKPOSTCTL] = {
+ .hsfreq = tclkpostctl,
+ .len = ARRAY_SIZE(tclkpostctl),
+ .base_value = 6,
+ },
+ [TCLKTRAILCTL] = {
+ .hsfreq = tclktrailctl,
+ .len = ARRAY_SIZE(tclktrailctl),
+ .base_value = 1,
+ },
+ [THSPRPRCTL] = {
+ .hsfreq = thsprprctl,
+ .len = ARRAY_SIZE(thsprprctl),
+ .base_value = 0,
+ },
+ [THSZEROCTL] = {
+ .hsfreq = thszeroctl,
+ .len = ARRAY_SIZE(thszeroctl),
+ .base_value = 0,
+ },
+ [THSTRAILCTL] = {
+ .hsfreq = thstrailctl,
+ .len = ARRAY_SIZE(thstrailctl),
+ .base_value = 3,
+ },
+ [TLPXCTL] = {
+ .hsfreq = tlpxctl,
+ .len = ARRAY_SIZE(tlpxctl),
+ .base_value = 0,
+ },
+ [THSEXITCTL] = {
+ .hsfreq = thsexitctl,
+ .len = ARRAY_SIZE(thsexitctl),
+ .base_value = 1,
+ },
+};
+
+/**
+ * rzv2h_dphy_find_ulpsexit - Find ULP Exit timing value based on frequency
+ * The function maps frequency ranges to ULP exit timing values.
+ * Thresholds in the local hsfreq[] are expressed in Hz already.
+ *
+ * @freq: Input frequency in Hz
+ *
+ * Return: ULP exit timing value
+ */
+static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
+{
+ /* Frequency thresholds in Hz for ULP exit timing selection */
+ static const unsigned long hsfreq[] = {
+ 1953125UL,
+ 3906250UL,
+ 7812500UL,
+ 15625000UL,
+ };
+ /* Corresponding ULP exit timing values for each frequency range */
+ static const u16 ulpsexit[] = {49, 98, 195, 391};
+ unsigned int i;
+
+ /* Find the appropriate frequency range */
+ for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
+ if (freq <= hsfreq[i])
+ break;
+ }
+
+ /* If frequency exceeds all thresholds, use the highest range */
+ if (i == ARRAY_SIZE(hsfreq))
+ i--;
+
+ return ulpsexit[i];
+}
+
+/**
+ * rzv2h_dphy_find_timings_val - Find timing parameter value from lookup tables
+ * @freq: Input frequency in Hz
+ * @index: Index to select timing parameter table (see enum rzv2h_dsi_timing_idx)
+ *
+ * Selects the timing table for the requested parameter, finds the
+ * frequency range entry and returns the register value to program:
+ *
+ * register_value = timings->base_value + table_index
+ *
+ * Note: frequency table entries are stored as small integers (units of 10):
+ * threshold_in_hz = (unsigned long)table_entry * 10 * MEGA
+ *
+ * Return: timing register value to be programmed into hardware
+ */
+static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
+{
+ const struct rzv2h_mipi_dsi_timings *timings;
+ u16 i;
+
+ /* Get the timing table structure for the requested parameter */
+ timings = &rzv2h_dsi_timings_tables[index];
+
+ /*
+ * Search through frequency table to find appropriate range
+ * timings->hsfreq[i] contains frequency values from HW manual
+ * Convert to Hz by multiplying by 10 * MEGA.
+ */
+ for (i = 0; i < timings->len; i++) {
+ unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
+
+ if (freq <= hsfreq)
+ break;
+ }
+
+ /* If frequency exceeds table range, use the last entry */
+ if (i == timings->len)
+ i--;
+
+ /*
+ * Calculate final register value:
+ * - timings->base_value: base value for this timing parameter
+ * - i: index into frequency table (0-based)
+ * Combined they give the exact register value to program
+ */
+ return timings->base_value + i;
+};
+
static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
{
iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
@@ -317,6 +573,169 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
return 0;
}
+static unsigned int rzv2h_dphy_mode_clk_check(struct rzg2l_mipi_dsi *dsi,
+ unsigned long mode_freq)
+{
+ u64 hsfreq_millihz, mode_freq_hz, mode_freq_millihz;
+ struct rzv2h_pll_div_pars cpg_dsi_parameters;
+ struct rzv2h_pll_pars dsi_parameters;
+ bool parameters_found;
+ unsigned int bpp;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ mode_freq_hz = mul_u32_u32(mode_freq, KILO);
+ mode_freq_millihz = mode_freq_hz * MILLI;
+ parameters_found =
+ rzv2h_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[0],
+ &cpg_dsi_parameters,
+ dsi->info->cpg_plldsi.table,
+ dsi->info->cpg_plldsi.table_size,
+ mode_freq_millihz);
+ if (!parameters_found)
+ return MODE_CLOCK_RANGE;
+
+ hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.div.freq_millihz * bpp,
+ dsi->lanes);
+ parameters_found = rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
+ &dsi_parameters, hsfreq_millihz);
+ if (!parameters_found)
+ return MODE_CLOCK_RANGE;
+
+ if (abs(dsi_parameters.error_millihz) >= 500)
+ return MODE_CLOCK_RANGE;
+
+ memcpy(&dsi->mode_calc.dsi_parameters, &dsi_parameters, sizeof(dsi_parameters));
+ dsi->mode_calc.mode_freq_khz = mode_freq;
+
+ return MODE_OK;
+}
+
+static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+ u64 *hsfreq_millihz)
+{
+ struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+ unsigned long status;
+
+ if (dsi->mode_calc.mode_freq_khz != mode_freq) {
+ status = rzv2h_dphy_mode_clk_check(dsi, mode_freq);
+ if (status != MODE_OK) {
+ dev_err(dsi->dev, "No PLL parameters found for mode clk %lu\n",
+ mode_freq);
+ return -EINVAL;
+ }
+ }
+
+ *hsfreq_millihz = dsi_parameters->freq_millihz;
+
+ return 0;
+}
+
+static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+ u64 hsfreq_millihz)
+{
+ struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+ unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
+ u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
+ struct rzg2l_mipi_dsi_timings dphy_timings;
+ u16 ulpsexit;
+ u64 hsfreq;
+
+ hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz, MILLI);
+
+ if (dsi_parameters->freq_millihz != hsfreq_millihz &&
+ !rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits, dsi_parameters,
+ hsfreq_millihz)) {
+ dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n", hsfreq);
+ return -EINVAL;
+ }
+
+ dphy_timings.tclk_trail =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKTRAILCTL);
+ dphy_timings.tclk_post =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL);
+ dphy_timings.tclk_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL);
+ dphy_timings.tclk_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL);
+ dphy_timings.ths_exit =
+ rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL);
+ dphy_timings.ths_trail =
+ rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL);
+ dphy_timings.ths_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL);
+ dphy_timings.ths_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL);
+ dphy_timings.tlpx =
+ rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL);
+ ulpsexit = rzv2h_dphy_find_ulpsexit(lpclk_rate);
+
+ phytclksetr = FIELD_PREP(PHYTCLKSETR_TCLKTRAILCTL, dphy_timings.tclk_trail) |
+ FIELD_PREP(PHYTCLKSETR_TCLKPOSTCTL, dphy_timings.tclk_post) |
+ FIELD_PREP(PHYTCLKSETR_TCLKZEROCTL, dphy_timings.tclk_zero) |
+ FIELD_PREP(PHYTCLKSETR_TCLKPRPRCTL, dphy_timings.tclk_prepare);
+ phythssetr = FIELD_PREP(PHYTHSSETR_THSEXITCTL, dphy_timings.ths_exit) |
+ FIELD_PREP(PHYTHSSETR_THSTRAILCTL, dphy_timings.ths_trail) |
+ FIELD_PREP(PHYTHSSETR_THSZEROCTL, dphy_timings.ths_zero) |
+ FIELD_PREP(PHYTHSSETR_THSPRPRCTL, dphy_timings.ths_prepare);
+ phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~PHYTLPXSETR_TLPXCTL;
+ phytlpxsetr |= FIELD_PREP(PHYTLPXSETR_TLPXCTL, dphy_timings.tlpx);
+ phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
+ phycr |= FIELD_PREP(PHYCR_ULPSEXIT, ulpsexit);
+
+ /* Setting all D-PHY Timings Registers */
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTCLKSETR, phytclksetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTHSSETR, phythssetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTLPXSETR, phytlpxsetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYCR, phycr);
+
+ rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET0R,
+ FIELD_PREP(PLLCLKSET0R_PLL_S, dsi_parameters->s) |
+ FIELD_PREP(PLLCLKSET0R_PLL_P, dsi_parameters->p) |
+ FIELD_PREP(PLLCLKSET0R_PLL_M, dsi_parameters->m));
+ rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R,
+ FIELD_PREP(PLLCLKSET1R_PLL_K, dsi_parameters->k));
+
+ /*
+ * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+ * (C) After write to D-PHY registers we need to wait for more than 1 x tp
+ *
+ * tp = 1 / (PLLREFCLK / PLLCLKSET0R.PLL_P)
+ * PLLREFCLK = 24MHz
+ * PLLCLKSET0R.PLL_P = {1, 2, 3, 4}
+ *
+ * To handle all the cases lets use PLLCLKSET0R.PLL_P = 4
+ * tp = 1 / (24MHz / 4) = 1 / 6MHz = 166.67ns
+ */
+ ndelay(200);
+
+ rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
+ /*
+ * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+ * (D) After write to PLLENR.PLLEN we need to wait for more than 3000 x tp
+ *
+ * 3000 x tp = 3000 x 0.16667 ns = 500.01 microseconds
+ */
+ usleep_range(510, 520);
+
+ return 0;
+}
+
+static void rzv2h_mipi_dsi_dphy_startup_late_init(struct rzg2l_mipi_dsi *dsi)
+{
+ /*
+ * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+ * (E) After write to TXSETR we need to wait for more than 200 microseconds
+ * and then write to PHYRSTR
+ */
+ usleep_range(210, 220);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYRSTR, PHYRSTR_PHYMRSTN);
+}
+
+static void rzv2h_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
+{
+ rzg2l_mipi_dsi_phy_write(dsi, PLLENR, 0);
+}
+
static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
const struct drm_display_mode *mode)
{
@@ -429,6 +848,9 @@ static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
case 18:
vich1ppsetr = VICH1PPSETR_DT_RGB18;
break;
+ case 16:
+ vich1ppsetr = VICH1PPSETR_DT_RGB16;
+ break;
}
if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) &&
@@ -979,6 +1401,10 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->vclk))
return PTR_ERR(dsi->vclk);
+ dsi->lpclk = devm_clk_get(dsi->dev, "lpclk");
+ if (IS_ERR(dsi->lpclk))
+ return PTR_ERR(dsi->lpclk);
+
dsi->rstc = devm_reset_control_get_optional_exclusive(dsi->dev, "rst");
if (IS_ERR(dsi->rstc))
return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
@@ -1051,6 +1477,32 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
+RZV2H_CPG_PLL_DSI_LIMITS(rzv2h_cpg_pll_dsi_limits);
+
+static const struct rzv2h_pll_limits *rzv2h_plldsi_limits[] = {
+ &rzv2h_cpg_pll_dsi_limits,
+};
+
+static const u8 rzv2h_cpg_div_table[] = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
+};
+
+static const struct rzg2l_mipi_dsi_hw_info rzv2h_mipi_dsi_info = {
+ .dphy_init = rzv2h_mipi_dsi_dphy_init,
+ .dphy_startup_late_init = rzv2h_mipi_dsi_dphy_startup_late_init,
+ .dphy_exit = rzv2h_mipi_dsi_dphy_exit,
+ .dphy_mode_clk_check = rzv2h_dphy_mode_clk_check,
+ .dphy_conf_clks = rzv2h_dphy_conf_clks,
+ .cpg_plldsi.limits = rzv2h_plldsi_limits,
+ .cpg_plldsi.table = rzv2h_cpg_div_table,
+ .cpg_plldsi.table_size = ARRAY_SIZE(rzv2h_cpg_div_table),
+ .phy_reg_offset = 0x10000,
+ .link_reg_offset = 0,
+ .min_dclk = 5440,
+ .max_dclk = 187500,
+ .features = RZ_MIPI_DSI_FEATURE_16BPP,
+};
+
static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
.dphy_init = rzg2l_mipi_dsi_dphy_init,
.dphy_exit = rzg2l_mipi_dsi_dphy_exit,
@@ -1061,6 +1513,7 @@ static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
};
static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
+ { .compatible = "renesas,r9a09g057-mipi-dsi", .data = &rzv2h_mipi_dsi_info, },
{ .compatible = "renesas,rzg2l-mipi-dsi", .data = &rzg2l_mipi_dsi_info, },
{ /* sentinel */ }
};
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
index d8082a87d874..2bef20566648 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
@@ -40,6 +40,39 @@
#define DSIDPHYTIM3_THS_TRAIL(x) ((x) << 8)
#define DSIDPHYTIM3_THS_ZERO(x) ((x) << 0)
+/* RZ/V2H DPHY Registers */
+#define PLLENR 0x000
+#define PLLENR_PLLEN BIT(0)
+
+#define PHYRSTR 0x004
+#define PHYRSTR_PHYMRSTN BIT(0)
+
+#define PLLCLKSET0R 0x010
+#define PLLCLKSET0R_PLL_S GENMASK(2, 0)
+#define PLLCLKSET0R_PLL_P GENMASK(13, 8)
+#define PLLCLKSET0R_PLL_M GENMASK(25, 16)
+
+#define PLLCLKSET1R 0x014
+#define PLLCLKSET1R_PLL_K GENMASK(15, 0)
+
+#define PHYTCLKSETR 0x020
+#define PHYTCLKSETR_TCLKTRAILCTL GENMASK(7, 0)
+#define PHYTCLKSETR_TCLKPOSTCTL GENMASK(15, 8)
+#define PHYTCLKSETR_TCLKZEROCTL GENMASK(23, 16)
+#define PHYTCLKSETR_TCLKPRPRCTL GENMASK(31, 24)
+
+#define PHYTHSSETR 0x024
+#define PHYTHSSETR_THSEXITCTL GENMASK(7, 0)
+#define PHYTHSSETR_THSTRAILCTL GENMASK(15, 8)
+#define PHYTHSSETR_THSZEROCTL GENMASK(23, 16)
+#define PHYTHSSETR_THSPRPRCTL GENMASK(31, 24)
+
+#define PHYTLPXSETR 0x028
+#define PHYTLPXSETR_TLPXCTL GENMASK(7, 0)
+
+#define PHYCR 0x030
+#define PHYCR_ULPSEXIT GENMASK(9, 0)
+
/* --------------------------------------------------------*/
/* Link Status Register */
@@ -130,6 +163,7 @@
/* Video-Input Channel 1 Pixel Packet Set Register */
#define VICH1PPSETR 0x420
+#define VICH1PPSETR_DT_RGB16 (0x0e << 16)
#define VICH1PPSETR_DT_RGB18 (0x1e << 16)
#define VICH1PPSETR_DT_RGB18_LS (0x2e << 16)
#define VICH1PPSETR_DT_RGB24 (0x3e << 16)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 727cdf768161..0dc1eb5d2ae3 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -467,6 +467,19 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
.use_drm_infoframe = true,
};
+static struct rockchip_hdmi_chip_data rk3368_chip_data = {
+ .lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = {
+ .mode_valid = dw_hdmi_rockchip_mode_valid,
+ .mpll_cfg = rockchip_mpll_cfg,
+ .cur_ctr = rockchip_cur_ctr,
+ .phy_config = rockchip_phy_config,
+ .phy_data = &rk3368_chip_data,
+ .use_drm_infoframe = true,
+};
+
static struct rockchip_hdmi_chip_data rk3399_chip_data = {
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
.lcdsel_big = FIELD_PREP_WM16_CONST(RK3399_HDMI_LCDC_SEL, 0),
@@ -507,6 +520,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
{ .compatible = "rockchip,rk3328-dw-hdmi",
.data = &rk3328_hdmi_drv_data
},
+ { .compatible = "rockchip,rk3368-dw-hdmi",
+ .data = &rk3368_hdmi_drv_data
+ },
{ .compatible = "rockchip,rk3399-dw-hdmi",
.data = &rk3399_hdmi_drv_data
},
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 1d4f1b822e7b..bd7936c03da2 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -344,7 +344,7 @@ drm_sched_rq_select_entity_fifo(struct drm_gpu_scheduler *sched,
*/
static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched)
{
- if (!READ_ONCE(sched->pause_submit))
+ if (!drm_sched_is_stopped(sched))
queue_work(sched->submit_wq, &sched->work_run_job);
}
@@ -354,7 +354,7 @@ static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched)
*/
static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched)
{
- if (!READ_ONCE(sched->pause_submit))
+ if (!drm_sched_is_stopped(sched))
queue_work(sched->submit_wq, &sched->work_free_job);
}
@@ -729,7 +729,9 @@ EXPORT_SYMBOL(drm_sched_start);
*
* Drivers can still save and restore their state for recovery operations, but
* we shouldn't make this a general scheduler feature around the dma_fence
- * interface.
+ * interface. The suggested driver-side replacement is to use
+ * drm_sched_for_each_pending_job() after stopping the scheduler and implement
+ * their own recovery operations.
*/
void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
{
@@ -1567,3 +1569,35 @@ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched)
queue_work(sched->submit_wq, &sched->work_free_job);
}
EXPORT_SYMBOL(drm_sched_wqueue_start);
+
+/**
+ * drm_sched_is_stopped() - Checks whether drm_sched is stopped
+ * @sched: DRM scheduler
+ *
+ * Return: true if sched is stopped, false otherwise
+ */
+bool drm_sched_is_stopped(struct drm_gpu_scheduler *sched)
+{
+ return READ_ONCE(sched->pause_submit);
+}
+EXPORT_SYMBOL(drm_sched_is_stopped);
+
+/**
+ * drm_sched_job_is_signaled() - DRM scheduler job is signaled
+ * @job: DRM scheduler job
+ *
+ * Determine if DRM scheduler job is signaled. DRM scheduler should be stopped
+ * to obtain a stable snapshot of state. Both parent fence (hardware fence) and
+ * finished fence (software fence) are checked to determine signaling state.
+ *
+ * Return: true if job is signaled, false otherwise
+ */
+bool drm_sched_job_is_signaled(struct drm_sched_job *job)
+{
+ struct drm_sched_fence *s_fence = job->s_fence;
+
+ WARN_ON(!drm_sched_is_stopped(job->sched));
+ return (s_fence->parent && dma_fence_is_signaled(s_fence->parent)) ||
+ dma_fence_is_signaled(&s_fence->finished);
+}
+EXPORT_SYMBOL(drm_sched_job_is_signaled);
diff --git a/drivers/gpu/drm/sitronix/Kconfig b/drivers/gpu/drm/sitronix/Kconfig
index 6de7d92d9b74..41a428ef8295 100644
--- a/drivers/gpu/drm/sitronix/Kconfig
+++ b/drivers/gpu/drm/sitronix/Kconfig
@@ -1,16 +1,44 @@
-config DRM_ST7571_I2C
- tristate "DRM support for Sitronix ST7571 display panels (I2C)"
- depends on DRM && I2C && MMU
+config DRM_ST7571
+ tristate "DRM support for Sitronix ST7567/ST7571 display panels"
+ depends on DRM && MMU
select DRM_CLIENT_SELECTION
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
- select REGMAP_I2C
select VIDEOMODE_HELPERS
help
- DRM driver for Sitronix ST7571 panels controlled over I2C.
+ Sitronix ST7571 is a driver and controller for 4-level gray
+ scale and monochrome dot matrix LCD panels.
+
+ DRM driver for Sitronix ST7567/ST7571 panels.
+ This is only the core driver, a driver for the appropriate bus
+ transport in your chip also must be selected.
+
+ if M is selected the module will be called st7571.
+
+config DRM_ST7571_I2C
+ tristate "DRM support for Sitronix ST7567/ST7571 display panels (I2C)"
+ depends on DRM_ST7571 && I2C
+ select REGMAP
+ help
+ Sitronix ST7571 is a driver and controller for 4-level gray
+ scale and monochrome dot matrix LCD panels.
+
+ DRM driver for Sitronix ST7565/ST7571 panels connected via I2C bus.
if M is selected the module will be called st7571-i2c.
+config DRM_ST7571_SPI
+ tristate "DRM support for Sitronix ST7567/ST7571 display panels (SPI)"
+ depends on DRM_ST7571 && SPI
+ select REGMAP_SPI
+ help
+ Sitronix ST7571 is a driver and controller for 4-level gray
+ scale and monochrome dot matrix LCD panels.
+
+ DRM driver for Sitronix ST7565/ST7571 panels connected via SPI bus.
+
+ if M is selected the module will be called st7571-spi.
+
config DRM_ST7586
tristate "DRM support for Sitronix ST7586 display panels"
depends on DRM && SPI
@@ -40,3 +68,13 @@ config DRM_ST7735R
If M is selected the module will be called st7735r.
+config DRM_ST7920
+ tristate "DRM support for Sitronix ST7920 LCD displays"
+ depends on DRM && SPI && MMU
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ select REGMAP_SPI
+ help
+ DRM driver for the ST7920 Sitronix LCD controllers.
+
+ If M is selected the module will be called st7920.
diff --git a/drivers/gpu/drm/sitronix/Makefile b/drivers/gpu/drm/sitronix/Makefile
index bd139e5a6995..d03beff37628 100644
--- a/drivers/gpu/drm/sitronix/Makefile
+++ b/drivers/gpu/drm/sitronix/Makefile
@@ -1,3 +1,6 @@
+obj-$(CONFIG_DRM_ST7571) += st7571.o
obj-$(CONFIG_DRM_ST7571_I2C) += st7571-i2c.o
+obj-$(CONFIG_DRM_ST7571_SPI) += st7571-spi.o
obj-$(CONFIG_DRM_ST7586) += st7586.o
obj-$(CONFIG_DRM_ST7735R) += st7735r.o
+obj-$(CONFIG_DRM_ST7920) += st7920.o
diff --git a/drivers/gpu/drm/sitronix/st7571-i2c.c b/drivers/gpu/drm/sitronix/st7571-i2c.c
index 4e73c8b415d6..44bc94be33d6 100644
--- a/drivers/gpu/drm/sitronix/st7571-i2c.c
+++ b/drivers/gpu/drm/sitronix/st7571-i2c.c
@@ -1,131 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Driver for Sitronix ST7571, a 4 level gray scale dot matrix LCD controller
+ * Driver for Sitronix ST7571 connected via I2C bus.
*
* Copyright (C) 2025 Marcus Folkesson <marcus.folkesson@gmail.com>
*/
-#include <linux/bitfield.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <drm/clients/drm_client_setup.h>
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_damage_helper.h>
-#include <drm/drm_drv.h>
-#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fbdev_shmem.h>
-#include <drm/drm_fourcc.h>
-#include <drm/drm_framebuffer.h>
-#include <drm/drm_gem_atomic_helper.h>
-#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_gem_shmem_helper.h>
-#include <drm/drm_modeset_helper_vtables.h>
-#include <drm/drm_module.h>
-#include <drm/drm_plane.h>
-#include <drm/drm_probe_helper.h>
+#include "st7571.h"
-#include <video/display_timing.h>
-#include <video/of_display_timing.h>
-
-#define ST7571_COMMAND_MODE (0x00)
-#define ST7571_DATA_MODE (0x40)
-
-/* Normal mode command set */
-#define ST7571_DISPLAY_OFF (0xae)
-#define ST7571_DISPLAY_ON (0xaf)
-#define ST7571_OSC_ON (0xab)
-#define ST7571_SET_COLUMN_LSB(c) (0x00 | FIELD_PREP(GENMASK(3, 0), (c)))
-#define ST7571_SET_COLUMN_MSB(c) (0x10 | FIELD_PREP(GENMASK(2, 0), (c) >> 4))
-#define ST7571_SET_COM0_LSB(x) (FIELD_PREP(GENMASK(6, 0), (x)))
-#define ST7571_SET_COM0_MSB (0x44)
-#define ST7571_SET_COM_SCAN_DIR(d) (0xc0 | FIELD_PREP(GENMASK(3, 3), (d)))
-#define ST7571_SET_CONTRAST_LSB(c) (FIELD_PREP(GENMASK(5, 0), (c)))
-#define ST7571_SET_CONTRAST_MSB (0x81)
-#define ST7571_SET_DISPLAY_DUTY_LSB(d) (FIELD_PREP(GENMASK(7, 0), (d)))
-#define ST7571_SET_DISPLAY_DUTY_MSB (0x48)
-#define ST7571_SET_ENTIRE_DISPLAY_ON(p) (0xa4 | FIELD_PREP(GENMASK(0, 0), (p)))
-#define ST7571_SET_LCD_BIAS(b) (0x50 | FIELD_PREP(GENMASK(2, 0), (b)))
-#define ST7571_SET_MODE_LSB(m) (FIELD_PREP(GENMASK(7, 2), (m)))
-#define ST7571_SET_MODE_MSB (0x38)
-#define ST7571_SET_PAGE(p) (0xb0 | FIELD_PREP(GENMASK(3, 0), (p)))
-#define ST7571_SET_POWER(p) (0x28 | FIELD_PREP(GENMASK(2, 0), (p)))
-#define ST7571_SET_REGULATOR_REG(r) (0x20 | FIELD_PREP(GENMASK(2, 0), (r)))
-#define ST7571_SET_REVERSE(r) (0xa6 | FIELD_PREP(GENMASK(0, 0), (r)))
-#define ST7571_SET_SEG_SCAN_DIR(d) (0xa0 | FIELD_PREP(GENMASK(0, 0), (d)))
-#define ST7571_SET_START_LINE_LSB(l) (FIELD_PREP(GENMASK(6, 0), (l)))
-#define ST7571_SET_START_LINE_MSB (0x40)
-
-/* Extension command set 3 */
-#define ST7571_COMMAND_SET_3 (0x7b)
-#define ST7571_SET_COLOR_MODE(c) (0x10 | FIELD_PREP(GENMASK(0, 0), (c)))
-#define ST7571_COMMAND_SET_NORMAL (0x00)
-
-/* ST7567 commands */
-#define ST7567_SET_LCD_BIAS(m) (0xa2 | FIELD_PREP(GENMASK(0, 0), (m)))
-
-#define ST7571_PAGE_HEIGHT 8
-
-#define DRIVER_NAME "st7571"
-#define DRIVER_DESC "ST7571 DRM driver"
-#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 0
-
-enum st7571_color_mode {
- ST7571_COLOR_MODE_GRAY = 0,
- ST7571_COLOR_MODE_BLACKWHITE = 1,
-};
-
-struct st7571_device;
-
-struct st7571_panel_constraints {
- u32 min_nlines;
- u32 max_nlines;
- u32 min_ncols;
- u32 max_ncols;
- bool support_grayscale;
-};
-
-struct st7571_panel_data {
- int (*init)(struct st7571_device *st7571);
- int (*parse_dt)(struct st7571_device *st7571);
- struct st7571_panel_constraints constraints;
-};
-
-struct st7571_panel_format {
- void (*prepare_buffer)(struct st7571_device *st7571,
- const struct iosys_map *vmap,
- struct drm_framebuffer *fb,
- struct drm_rect *rect,
- struct drm_format_conv_state *fmtcnv_state);
- int (*update_rect)(struct drm_framebuffer *fb, struct drm_rect *rect);
- enum st7571_color_mode mode;
- const u8 nformats;
- const u32 formats[];
-};
-
-struct st7571_device {
- struct drm_device dev;
-
- struct drm_plane primary_plane;
- struct drm_crtc crtc;
- struct drm_encoder encoder;
- struct drm_connector connector;
-
- struct drm_display_mode mode;
-
- const struct st7571_panel_format *pformat;
- const struct st7571_panel_data *pdata;
+struct st7571_i2c_transport {
struct i2c_client *client;
- struct gpio_desc *reset;
- struct regmap *regmap;
/*
* Depending on the hardware design, the acknowledge signal may be hard to
@@ -149,42 +36,21 @@ struct st7571_device {
*
*/
bool ignore_nak;
-
- bool grayscale;
- bool inverted;
- u32 height_mm;
- u32 width_mm;
- u32 startline;
- u32 nlines;
- u32 ncols;
- u32 bpp;
-
- /* Intermediate buffer in LCD friendly format */
- u8 *hwbuf;
-
- /* Row of (transformed) pixels ready to be written to the display */
- u8 *row;
};
-static inline struct st7571_device *drm_to_st7571(struct drm_device *dev)
-{
- return container_of(dev, struct st7571_device, dev);
-}
-
-static int st7571_regmap_write(void *context, const void *data, size_t count)
+static int st7571_i2c_regmap_write(void *context, const void *data, size_t count)
{
- struct i2c_client *client = context;
- struct st7571_device *st7571 = i2c_get_clientdata(client);
+ struct st7571_i2c_transport *t = context;
int ret;
struct i2c_msg msg = {
- .addr = st7571->client->addr,
- .flags = st7571->ignore_nak ? I2C_M_IGNORE_NAK : 0,
+ .addr = t->client->addr,
+ .flags = t->ignore_nak ? I2C_M_IGNORE_NAK : 0,
.len = count,
.buf = (u8 *)data
};
- ret = i2c_transfer(st7571->client->adapter, &msg, 1);
+ ret = i2c_transfer(t->client->adapter, &msg, 1);
/*
* Unfortunately, there is no way to check if the transfer failed because of
@@ -192,770 +58,41 @@ static int st7571_regmap_write(void *context, const void *data, size_t count)
*
* However, if the transfer fails and ignore_nak is set, we know it is an error.
*/
- if (ret < 0 && st7571->ignore_nak)
+ if (ret < 0 && t->ignore_nak)
return ret;
return 0;
}
/* The st7571 driver does not read registers but regmap expects a .read */
-static int st7571_regmap_read(void *context, const void *reg_buf,
- size_t reg_size, void *val_buf, size_t val_size)
+static int st7571_i2c_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
{
return -EOPNOTSUPP;
}
-static int st7571_send_command_list(struct st7571_device *st7571,
- const u8 *cmd_list, size_t len)
-{
- int ret;
-
- for (int i = 0; i < len; i++) {
- ret = regmap_write(st7571->regmap, ST7571_COMMAND_MODE, cmd_list[i]);
- if (ret < 0)
- return ret;
- }
-
- return ret;
-}
-
-static inline u8 st7571_transform_xy(const char *p, int x, int y, u8 bpp)
-{
- int xrest = x % 8;
- u8 result = 0;
- u8 row_len = 16 * bpp;
-
- /*
- * Transforms an (x, y) pixel coordinate into a vertical 8-bit
- * column from the framebuffer. It calculates the corresponding byte in the
- * framebuffer, extracts the bit at the given x position across 8 consecutive
- * rows, and packs those bits into a single byte.
- *
- * Return an 8-bit value representing a vertical column of pixels.
- */
- x = x / 8;
- y = (y / 8) * 8;
-
- for (int i = 0; i < 8; i++) {
- int row_idx = y + i;
- u8 byte = p[row_idx * row_len + x];
- u8 bit = (byte >> xrest) & 1;
-
- result |= (bit << i);
- }
-
- return result;
-}
-
-static int st7571_set_position(struct st7571_device *st7571, int x, int y)
-{
- u8 cmd_list[] = {
- ST7571_SET_COLUMN_LSB(x),
- ST7571_SET_COLUMN_MSB(x),
- ST7571_SET_PAGE(y / ST7571_PAGE_HEIGHT),
- };
-
- return st7571_send_command_list(st7571, cmd_list, ARRAY_SIZE(cmd_list));
-}
-
-static int st7571_fb_clear_screen(struct st7571_device *st7571)
-{
- u32 npixels = st7571->ncols * round_up(st7571->nlines, ST7571_PAGE_HEIGHT) * st7571->bpp;
- char pixelvalue = 0x00;
-
- st7571_set_position(st7571, 0, 0);
- for (int i = 0; i < npixels; i++)
- regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, &pixelvalue, 1);
-
- return 0;
-}
-
-static void st7571_prepare_buffer_monochrome(struct st7571_device *st7571,
- const struct iosys_map *vmap,
- struct drm_framebuffer *fb,
- struct drm_rect *rect,
- struct drm_format_conv_state *fmtcnv_state)
-{
- unsigned int dst_pitch;
- struct iosys_map dst;
- u32 size;
-
- switch (fb->format->format) {
- case DRM_FORMAT_XRGB8888:
- dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
- iosys_map_set_vaddr(&dst, st7571->hwbuf);
-
- drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
- break;
-
- case DRM_FORMAT_R1:
- size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
- memcpy(st7571->hwbuf, vmap->vaddr, size);
- break;
- }
-}
-
-static void st7571_prepare_buffer_grayscale(struct st7571_device *st7571,
- const struct iosys_map *vmap,
- struct drm_framebuffer *fb,
- struct drm_rect *rect,
- struct drm_format_conv_state *fmtcnv_state)
-{
- u32 size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
- unsigned int dst_pitch;
- struct iosys_map dst;
-
- switch (fb->format->format) {
- case DRM_FORMAT_XRGB8888:
- dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 4);
- iosys_map_set_vaddr(&dst, st7571->hwbuf);
-
- drm_fb_xrgb8888_to_gray2(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
- break;
-
- case DRM_FORMAT_R1:
- size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
- memcpy(st7571->hwbuf, vmap->vaddr, size);
- break;
-
- case DRM_FORMAT_R2:
- size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 4;
- memcpy(st7571->hwbuf, vmap->vaddr, size);
- break;
- }
-}
-
-static int st7571_fb_update_rect_monochrome(struct drm_framebuffer *fb, struct drm_rect *rect)
-{
- struct st7571_device *st7571 = drm_to_st7571(fb->dev);
- char *row = st7571->row;
-
- /* Align y to display page boundaries */
- rect->y1 = round_down(rect->y1, ST7571_PAGE_HEIGHT);
- rect->y2 = min_t(unsigned int, round_up(rect->y2, ST7571_PAGE_HEIGHT), st7571->nlines);
-
- for (int y = rect->y1; y < rect->y2; y += ST7571_PAGE_HEIGHT) {
- for (int x = rect->x1; x < rect->x2; x++)
- row[x] = st7571_transform_xy(st7571->hwbuf, x, y, 1);
-
- st7571_set_position(st7571, rect->x1, y);
-
- /* TODO: Investige why we can't write multiple bytes at once */
- for (int x = rect->x1; x < rect->x2; x++)
- regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
- }
-
- return 0;
-}
-
-static int st7571_fb_update_rect_grayscale(struct drm_framebuffer *fb, struct drm_rect *rect)
-{
- struct st7571_device *st7571 = drm_to_st7571(fb->dev);
- u32 format = fb->format->format;
- char *row = st7571->row;
- int x1;
- int x2;
-
- /* Align y to display page boundaries */
- rect->y1 = round_down(rect->y1, ST7571_PAGE_HEIGHT);
- rect->y2 = min_t(unsigned int, round_up(rect->y2, ST7571_PAGE_HEIGHT), st7571->nlines);
-
- switch (format) {
- case DRM_FORMAT_R1:
- x1 = rect->x1 * 1;
- x2 = rect->x2 * 1;
- break;
- case DRM_FORMAT_R2:
- fallthrough;
- case DRM_FORMAT_XRGB8888:
- x1 = rect->x1 * 2;
- x2 = rect->x2 * 2;
- break;
- }
-
- for (int y = rect->y1; y < rect->y2; y += ST7571_PAGE_HEIGHT) {
- for (int x = x1; x < x2; x++)
- row[x] = st7571_transform_xy(st7571->hwbuf, x, y, 2);
-
- st7571_set_position(st7571, rect->x1, y);
-
- /* TODO: Investige why we can't write multiple bytes at once */
- for (int x = x1; x < x2; x++) {
- regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
-
- /*
- * As the display supports grayscale, all pixels must be written as two bits
- * even if the format is monochrome.
- *
- * The bit values maps to the following grayscale:
- * 0 0 = Black
- * 0 1 = Dark gray
- * 1 0 = Light gray
- * 1 1 = White
- *
- * For monochrome formats, write the same value twice to get
- * either a black or white pixel.
- */
- if (format == DRM_FORMAT_R1)
- regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
- }
- }
-
- return 0;
-}
-
-static int st7571_connector_get_modes(struct drm_connector *conn)
-{
- struct st7571_device *st7571 = drm_to_st7571(conn->dev);
-
- return drm_connector_helper_get_modes_fixed(conn, &st7571->mode);
-}
-
-static const struct drm_connector_helper_funcs st7571_connector_helper_funcs = {
- .get_modes = st7571_connector_get_modes,
-};
-
-static const struct st7571_panel_format st7571_monochrome = {
- .prepare_buffer = st7571_prepare_buffer_monochrome,
- .update_rect = st7571_fb_update_rect_monochrome,
- .mode = ST7571_COLOR_MODE_BLACKWHITE,
- .formats = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_R1,
- },
- .nformats = 2,
-};
-
-static const struct st7571_panel_format st7571_grayscale = {
- .prepare_buffer = st7571_prepare_buffer_grayscale,
- .update_rect = st7571_fb_update_rect_grayscale,
- .mode = ST7571_COLOR_MODE_GRAY,
- .formats = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_R1,
- DRM_FORMAT_R2,
- },
- .nformats = 3,
-};
-
-static const u64 st7571_primary_plane_fmtmods[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
-};
-
-static int st7571_primary_plane_helper_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_crtc *new_crtc = new_plane_state->crtc;
- struct drm_crtc_state *new_crtc_state = NULL;
-
- if (new_crtc)
- new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
-
- return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
-}
-
-static void st7571_primary_plane_helper_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_framebuffer *fb = plane_state->fb;
- struct drm_atomic_helper_damage_iter iter;
- struct drm_device *dev = plane->dev;
- struct drm_rect damage;
- struct st7571_device *st7571 = drm_to_st7571(plane->dev);
- int ret, idx;
-
- if (!fb)
- return; /* no framebuffer; plane is disabled */
-
- ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
- if (ret)
- return;
-
- if (!drm_dev_enter(dev, &idx))
- goto out_drm_gem_fb_end_cpu_access;
-
- drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
- drm_atomic_for_each_plane_damage(&iter, &damage) {
- st7571->pformat->prepare_buffer(st7571,
- &shadow_plane_state->data[0],
- fb, &damage,
- &shadow_plane_state->fmtcnv_state);
-
- st7571->pformat->update_rect(fb, &damage);
- }
-
- drm_dev_exit(idx);
-
-out_drm_gem_fb_end_cpu_access:
- drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-}
-
-static void st7571_primary_plane_helper_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_device *dev = plane->dev;
- struct st7571_device *st7571 = drm_to_st7571(plane->dev);
- int idx;
-
- if (!drm_dev_enter(dev, &idx))
- return;
-
- st7571_fb_clear_screen(st7571);
- drm_dev_exit(idx);
-}
-
-static const struct drm_plane_helper_funcs st7571_primary_plane_helper_funcs = {
- DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
- .atomic_check = st7571_primary_plane_helper_atomic_check,
- .atomic_update = st7571_primary_plane_helper_atomic_update,
- .atomic_disable = st7571_primary_plane_helper_atomic_disable,
-};
-
-static const struct drm_plane_funcs st7571_primary_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
- DRM_GEM_SHADOW_PLANE_FUNCS,
-};
-
-/*
- * CRTC
- */
-
-static enum drm_mode_status st7571_crtc_mode_valid(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
-{
- struct st7571_device *st7571 = drm_to_st7571(crtc->dev);
-
- return drm_crtc_helper_mode_valid_fixed(crtc, mode, &st7571->mode);
-}
-
-static const struct drm_crtc_helper_funcs st7571_crtc_helper_funcs = {
- .atomic_check = drm_crtc_helper_atomic_check,
- .mode_valid = st7571_crtc_mode_valid,
-};
-
-static const struct drm_crtc_funcs st7571_crtc_funcs = {
- .reset = drm_atomic_helper_crtc_reset,
- .destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
-};
-
-/*
- * Encoder
- */
-
-static void st7571_encoder_atomic_enable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
-{
- struct drm_device *drm = encoder->dev;
- struct st7571_device *st7571 = drm_to_st7571(drm);
- u8 command = ST7571_DISPLAY_ON;
- int ret;
-
- ret = st7571->pdata->init(st7571);
- if (ret)
- return;
-
- st7571_send_command_list(st7571, &command, 1);
-}
-
-static void st7571_encoder_atomic_disable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
-{
- struct drm_device *drm = encoder->dev;
- struct st7571_device *st7571 = drm_to_st7571(drm);
- u8 command = ST7571_DISPLAY_OFF;
-
- st7571_send_command_list(st7571, &command, 1);
-}
-
-static const struct drm_encoder_funcs st7571_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-
-};
-
-static const struct drm_encoder_helper_funcs st7571_encoder_helper_funcs = {
- .atomic_enable = st7571_encoder_atomic_enable,
- .atomic_disable = st7571_encoder_atomic_disable,
-};
-
-/*
- * Connector
- */
-
-static const struct drm_connector_funcs st7571_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+static const struct regmap_bus st7571_i2c_regmap_bus = {
+ .read = st7571_i2c_regmap_read,
+ .write = st7571_i2c_regmap_write,
};
-static const struct drm_mode_config_funcs st7571_mode_config_funcs = {
- .fb_create = drm_gem_fb_create_with_dirty,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
-};
-
-static struct drm_display_mode st7571_mode(struct st7571_device *st7571)
-{
- struct drm_display_mode mode = {
- DRM_SIMPLE_MODE(st7571->ncols, st7571->nlines,
- st7571->width_mm, st7571->height_mm),
- };
-
- return mode;
-}
-
-static int st7571_mode_config_init(struct st7571_device *st7571)
-{
- struct drm_device *dev = &st7571->dev;
- const struct st7571_panel_constraints *constraints = &st7571->pdata->constraints;
- int ret;
-
- ret = drmm_mode_config_init(dev);
- if (ret)
- return ret;
-
- dev->mode_config.min_width = constraints->min_ncols;
- dev->mode_config.min_height = constraints->min_nlines;
- dev->mode_config.max_width = constraints->max_ncols;
- dev->mode_config.max_height = constraints->max_nlines;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.funcs = &st7571_mode_config_funcs;
-
- return 0;
-}
-
-static int st7571_plane_init(struct st7571_device *st7571,
- const struct st7571_panel_format *pformat)
-{
- struct drm_plane *primary_plane = &st7571->primary_plane;
- struct drm_device *dev = &st7571->dev;
- int ret;
-
- ret = drm_universal_plane_init(dev, primary_plane, 0,
- &st7571_primary_plane_funcs,
- pformat->formats,
- pformat->nformats,
- st7571_primary_plane_fmtmods,
- DRM_PLANE_TYPE_PRIMARY, NULL);
- if (ret)
- return ret;
-
- drm_plane_helper_add(primary_plane, &st7571_primary_plane_helper_funcs);
- drm_plane_enable_fb_damage_clips(primary_plane);
-
- return 0;
-}
-
-static int st7571_crtc_init(struct st7571_device *st7571)
-{
- struct drm_plane *primary_plane = &st7571->primary_plane;
- struct drm_crtc *crtc = &st7571->crtc;
- struct drm_device *dev = &st7571->dev;
- int ret;
-
- ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
- &st7571_crtc_funcs, NULL);
- if (ret)
- return ret;
-
- drm_crtc_helper_add(crtc, &st7571_crtc_helper_funcs);
-
- return 0;
-}
-
-static int st7571_encoder_init(struct st7571_device *st7571)
-{
- struct drm_encoder *encoder = &st7571->encoder;
- struct drm_crtc *crtc = &st7571->crtc;
- struct drm_device *dev = &st7571->dev;
- int ret;
-
- ret = drm_encoder_init(dev, encoder, &st7571_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL);
- if (ret)
- return ret;
-
- drm_encoder_helper_add(encoder, &st7571_encoder_helper_funcs);
-
- encoder->possible_crtcs = drm_crtc_mask(crtc);
-
- return 0;
-}
-
-static int st7571_connector_init(struct st7571_device *st7571)
-{
- struct drm_connector *connector = &st7571->connector;
- struct drm_encoder *encoder = &st7571->encoder;
- struct drm_device *dev = &st7571->dev;
- int ret;
-
- ret = drm_connector_init(dev, connector, &st7571_connector_funcs,
- DRM_MODE_CONNECTOR_Unknown);
- if (ret)
- return ret;
-
- drm_connector_helper_add(connector, &st7571_connector_helper_funcs);
-
- return drm_connector_attach_encoder(connector, encoder);
-}
-
-DEFINE_DRM_GEM_FOPS(st7571_fops);
-
-static const struct drm_driver st7571_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
-
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
-
- .fops = &st7571_fops,
- DRM_GEM_SHMEM_DRIVER_OPS,
- DRM_FBDEV_SHMEM_DRIVER_OPS,
-};
-
-static const struct regmap_bus st7571_regmap_bus = {
- .read = st7571_regmap_read,
- .write = st7571_regmap_write,
-};
-
-static const struct regmap_config st7571_regmap_config = {
+static const struct regmap_config st7571_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.use_single_write = true,
};
-static int st7571_validate_parameters(struct st7571_device *st7571)
-{
- struct device *dev = st7571->dev.dev;
- const struct st7571_panel_constraints *constraints = &st7571->pdata->constraints;
-
- if (st7571->width_mm == 0) {
- dev_err(dev, "Invalid panel width\n");
- return -EINVAL;
- }
-
- if (st7571->height_mm == 0) {
- dev_err(dev, "Invalid panel height\n");
- return -EINVAL;
- }
-
- if (st7571->nlines < constraints->min_nlines ||
- st7571->nlines > constraints->max_nlines) {
- dev_err(dev, "Invalid timing configuration.\n");
- return -EINVAL;
- }
-
- if (st7571->startline + st7571->nlines > constraints->max_nlines) {
- dev_err(dev, "Invalid timing configuration.\n");
- return -EINVAL;
- }
-
- if (st7571->ncols < constraints->min_ncols ||
- st7571->ncols > constraints->max_ncols) {
- dev_err(dev, "Invalid timing configuration.\n");
- return -EINVAL;
- }
-
- if (st7571->grayscale && !constraints->support_grayscale) {
- dev_err(dev, "Grayscale not supported\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int st7567_parse_dt(struct st7571_device *st7567)
-{
- struct device *dev = &st7567->client->dev;
- struct device_node *np = dev->of_node;
- struct display_timing dt;
- int ret;
-
- ret = of_get_display_timing(np, "panel-timing", &dt);
- if (ret) {
- dev_err(dev, "Failed to get display timing from DT\n");
- return ret;
- }
-
- of_property_read_u32(np, "width-mm", &st7567->width_mm);
- of_property_read_u32(np, "height-mm", &st7567->height_mm);
- st7567->inverted = of_property_read_bool(np, "sitronix,inverted");
-
- st7567->pformat = &st7571_monochrome;
- st7567->bpp = 1;
-
- st7567->startline = dt.vfront_porch.typ;
- st7567->nlines = dt.vactive.typ;
- st7567->ncols = dt.hactive.typ;
-
- return 0;
-}
-
-static int st7571_parse_dt(struct st7571_device *st7571)
-{
- struct device *dev = &st7571->client->dev;
- struct device_node *np = dev->of_node;
- struct display_timing dt;
- int ret;
-
- ret = of_get_display_timing(np, "panel-timing", &dt);
- if (ret) {
- dev_err(dev, "Failed to get display timing from DT\n");
- return ret;
- }
-
- of_property_read_u32(np, "width-mm", &st7571->width_mm);
- of_property_read_u32(np, "height-mm", &st7571->height_mm);
- st7571->grayscale = of_property_read_bool(np, "sitronix,grayscale");
- st7571->inverted = of_property_read_bool(np, "sitronix,inverted");
-
- if (st7571->grayscale) {
- st7571->pformat = &st7571_grayscale;
- st7571->bpp = 2;
- } else {
- st7571->pformat = &st7571_monochrome;
- st7571->bpp = 1;
- }
-
- st7571->startline = dt.vfront_porch.typ;
- st7571->nlines = dt.vactive.typ;
- st7571->ncols = dt.hactive.typ;
-
- st7571->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(st7571->reset))
- return dev_err_probe(dev, PTR_ERR(st7571->reset),
- "Failed to get reset gpio\n");
-
-
- return 0;
-}
-
-static void st7571_reset(struct st7571_device *st7571)
-{
- gpiod_set_value_cansleep(st7571->reset, 1);
- fsleep(20);
- gpiod_set_value_cansleep(st7571->reset, 0);
-}
-
-static int st7567_lcd_init(struct st7571_device *st7567)
-{
- /*
- * Most of the initialization sequence is taken directly from the
- * referential initial code in the ST7567 datasheet.
- */
- u8 commands[] = {
- ST7571_DISPLAY_OFF,
-
- ST7567_SET_LCD_BIAS(1),
-
- ST7571_SET_SEG_SCAN_DIR(0),
- ST7571_SET_COM_SCAN_DIR(1),
-
- ST7571_SET_REGULATOR_REG(4),
- ST7571_SET_CONTRAST_MSB,
- ST7571_SET_CONTRAST_LSB(0x20),
-
- ST7571_SET_START_LINE_MSB,
- ST7571_SET_START_LINE_LSB(st7567->startline),
-
- ST7571_SET_POWER(0x4), /* Power Control, VC: ON, VR: OFF, VF: OFF */
- ST7571_SET_POWER(0x6), /* Power Control, VC: ON, VR: ON, VF: OFF */
- ST7571_SET_POWER(0x7), /* Power Control, VC: ON, VR: ON, VF: ON */
-
- ST7571_SET_REVERSE(st7567->inverted ? 1 : 0),
- ST7571_SET_ENTIRE_DISPLAY_ON(0),
- };
-
- return st7571_send_command_list(st7567, commands, ARRAY_SIZE(commands));
-}
-
-static int st7571_lcd_init(struct st7571_device *st7571)
-{
- /*
- * Most of the initialization sequence is taken directly from the
- * referential initial code in the ST7571 datasheet.
- */
- u8 commands[] = {
- ST7571_DISPLAY_OFF,
-
- ST7571_SET_MODE_MSB,
- ST7571_SET_MODE_LSB(0x2e),
-
- ST7571_SET_SEG_SCAN_DIR(0),
- ST7571_SET_COM_SCAN_DIR(1),
-
- ST7571_SET_COM0_MSB,
- ST7571_SET_COM0_LSB(0x00),
-
- ST7571_SET_START_LINE_MSB,
- ST7571_SET_START_LINE_LSB(st7571->startline),
-
- ST7571_OSC_ON,
- ST7571_SET_REGULATOR_REG(5),
- ST7571_SET_CONTRAST_MSB,
- ST7571_SET_CONTRAST_LSB(0x33),
- ST7571_SET_LCD_BIAS(0x04),
- ST7571_SET_DISPLAY_DUTY_MSB,
- ST7571_SET_DISPLAY_DUTY_LSB(st7571->nlines),
-
- ST7571_SET_POWER(0x4), /* Power Control, VC: ON, VR: OFF, VF: OFF */
- ST7571_SET_POWER(0x6), /* Power Control, VC: ON, VR: ON, VF: OFF */
- ST7571_SET_POWER(0x7), /* Power Control, VC: ON, VR: ON, VF: ON */
-
- ST7571_COMMAND_SET_3,
- ST7571_SET_COLOR_MODE(st7571->pformat->mode),
- ST7571_COMMAND_SET_NORMAL,
-
- ST7571_SET_REVERSE(st7571->inverted ? 1 : 0),
- ST7571_SET_ENTIRE_DISPLAY_ON(0),
- };
-
- /* Perform a reset before initializing the controller */
- st7571_reset(st7571);
-
- return st7571_send_command_list(st7571, commands, ARRAY_SIZE(commands));
-}
-
-static int st7571_probe(struct i2c_client *client)
+static int st7571_i2c_probe(struct i2c_client *client)
{
struct st7571_device *st7571;
- struct drm_device *dev;
- int ret;
-
- st7571 = devm_drm_dev_alloc(&client->dev, &st7571_driver,
- struct st7571_device, dev);
- if (IS_ERR(st7571))
- return PTR_ERR(st7571);
-
- dev = &st7571->dev;
- st7571->client = client;
- i2c_set_clientdata(client, st7571);
- st7571->pdata = device_get_match_data(&client->dev);
-
- ret = st7571->pdata->parse_dt(st7571);
- if (ret)
- return ret;
+ struct st7571_i2c_transport *t;
+ struct regmap *regmap;
- ret = st7571_validate_parameters(st7571);
- if (ret)
- return ret;
+ t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
- st7571->mode = st7571_mode(st7571);
+ t->client = client;
/*
* The hardware design could make it hard to detect a NAK on the I2C bus.
@@ -964,94 +101,31 @@ static int st7571_probe(struct i2c_client *client)
* cruft in the logs.
*/
if (i2c_check_functionality(client->adapter, I2C_FUNC_PROTOCOL_MANGLING))
- st7571->ignore_nak = true;
+ t->ignore_nak = true;
- st7571->regmap = devm_regmap_init(&client->dev, &st7571_regmap_bus,
- client, &st7571_regmap_config);
- if (IS_ERR(st7571->regmap)) {
- return dev_err_probe(&client->dev, PTR_ERR(st7571->regmap),
+ regmap = devm_regmap_init(&client->dev, &st7571_i2c_regmap_bus,
+ t, &st7571_i2c_regmap_config);
+ if (IS_ERR(regmap)) {
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
"Failed to initialize regmap\n");
}
- st7571->hwbuf = devm_kzalloc(&client->dev,
- (st7571->nlines * st7571->ncols * st7571->bpp) / 8,
- GFP_KERNEL);
- if (!st7571->hwbuf)
- return -ENOMEM;
-
- st7571->row = devm_kzalloc(&client->dev,
- (st7571->ncols * st7571->bpp),
- GFP_KERNEL);
- if (!st7571->row)
- return -ENOMEM;
-
- ret = st7571_mode_config_init(st7571);
- if (ret)
- return dev_err_probe(&client->dev, ret,
- "Failed to initialize mode config\n");
-
- ret = st7571_plane_init(st7571, st7571->pformat);
- if (ret)
- return dev_err_probe(&client->dev, ret,
- "Failed to initialize primary plane\n");
-
- ret = st7571_crtc_init(st7571);
- if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "Failed to initialize CRTC\n");
-
- ret = st7571_encoder_init(st7571);
- if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "Failed to initialize encoder\n");
-
- ret = st7571_connector_init(st7571);
- if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "Failed to initialize connector\n");
-
- drm_mode_config_reset(dev);
-
- ret = drm_dev_register(dev, 0);
- if (ret)
- return dev_err_probe(&client->dev, ret,
- "Failed to register DRM device\n");
+ st7571 = st7571_probe(&client->dev, regmap);
+ if (IS_ERR(st7571))
+ return dev_err_probe(&client->dev, PTR_ERR(st7571),
+ "Failed to initialize regmap\n");
- drm_client_setup(dev, NULL);
+ i2c_set_clientdata(client, st7571);
return 0;
}
-static void st7571_remove(struct i2c_client *client)
+static void st7571_i2c_remove(struct i2c_client *client)
{
struct st7571_device *st7571 = i2c_get_clientdata(client);
- drm_dev_unplug(&st7571->dev);
+ st7571_remove(st7571);
}
-static const struct st7571_panel_data st7567_config = {
- .init = st7567_lcd_init,
- .parse_dt = st7567_parse_dt,
- .constraints = {
- .min_nlines = 1,
- .max_nlines = 64,
- .min_ncols = 128,
- .max_ncols = 128,
- .support_grayscale = false,
- },
-};
-
-static const struct st7571_panel_data st7571_config = {
- .init = st7571_lcd_init,
- .parse_dt = st7571_parse_dt,
- .constraints = {
- .min_nlines = 1,
- .max_nlines = 128,
- .min_ncols = 128,
- .max_ncols = 128,
- .support_grayscale = true,
- },
-};
-
static const struct of_device_id st7571_of_match[] = {
{ .compatible = "sitronix,st7567", .data = &st7567_config },
{ .compatible = "sitronix,st7571", .data = &st7571_config },
@@ -1068,16 +142,17 @@ MODULE_DEVICE_TABLE(i2c, st7571_id);
static struct i2c_driver st7571_i2c_driver = {
.driver = {
- .name = "st7571",
+ .name = "st7571-i2c",
.of_match_table = st7571_of_match,
},
- .probe = st7571_probe,
- .remove = st7571_remove,
+ .probe = st7571_i2c_probe,
+ .remove = st7571_i2c_remove,
.id_table = st7571_id,
};
module_i2c_driver(st7571_i2c_driver);
MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
-MODULE_DESCRIPTION("DRM Driver for Sitronix ST7571 LCD controller");
+MODULE_DESCRIPTION("DRM Driver for Sitronix ST7571 LCD controller (I2C)");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("DRM_ST7571");
diff --git a/drivers/gpu/drm/sitronix/st7571-spi.c b/drivers/gpu/drm/sitronix/st7571-spi.c
new file mode 100644
index 000000000000..0206e9162f1c
--- /dev/null
+++ b/drivers/gpu/drm/sitronix/st7571-spi.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Sitronix ST7571 connected via SPI bus.
+ *
+ * Copyright (C) 2025 Marcus Folkesson <marcus.folkesson@gmail.com>
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "st7571.h"
+
+static const struct regmap_config st7571_spi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .can_multi_write = true,
+};
+
+static int st7571_spi_probe(struct spi_device *spi)
+{
+ struct st7571_device *st7571;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &st7571_spi_regmap_config);
+ if (IS_ERR(regmap)) {
+ return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+ "Failed to initialize regmap\n");
+ }
+
+ st7571 = st7571_probe(&spi->dev, regmap);
+ if (IS_ERR(st7571))
+ return dev_err_probe(&spi->dev, PTR_ERR(st7571),
+ "Failed to initialize regmap\n");
+
+ spi_set_drvdata(spi, st7571);
+ return 0;
+}
+
+static void st7571_spi_remove(struct spi_device *spi)
+{
+ struct st7571_device *st7571 = spi_get_drvdata(spi);
+
+ st7571_remove(st7571);
+}
+
+static const struct of_device_id st7571_of_match[] = {
+ { .compatible = "sitronix,st7567", .data = &st7567_config },
+ { .compatible = "sitronix,st7571", .data = &st7571_config },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st7571_of_match);
+
+static const struct spi_device_id st7571_spi_id[] = {
+ { "st7567", 0 },
+ { "st7571", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, st7571_spi_id);
+
+static struct spi_driver st7571_spi_driver = {
+ .driver = {
+ .name = "st7571-spi",
+ .of_match_table = st7571_of_match,
+ },
+ .probe = st7571_spi_probe,
+ .remove = st7571_spi_remove,
+ .id_table = st7571_spi_id,
+};
+
+module_spi_driver(st7571_spi_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("DRM Driver for Sitronix ST7571 LCD controller (SPI)");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("DRM_ST7571");
diff --git a/drivers/gpu/drm/sitronix/st7571.c b/drivers/gpu/drm/sitronix/st7571.c
new file mode 100644
index 000000000000..5fd575d972a2
--- /dev/null
+++ b/drivers/gpu/drm/sitronix/st7571.c
@@ -0,0 +1,918 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Sitronix ST7571, a 4 level gray scale dot matrix LCD controller
+ *
+ * Copyright (C) 2025 Marcus Folkesson <marcus.folkesson@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_shmem.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_module.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+
+#include "st7571.h"
+
+#define ST7571_COMMAND_MODE (0x00)
+#define ST7571_DATA_MODE (0x40)
+
+/* Normal mode command set */
+#define ST7571_DISPLAY_OFF (0xae)
+#define ST7571_DISPLAY_ON (0xaf)
+#define ST7571_OSC_ON (0xab)
+#define ST7571_SET_COLUMN_LSB(c) (0x00 | FIELD_PREP(GENMASK(3, 0), (c)))
+#define ST7571_SET_COLUMN_MSB(c) (0x10 | FIELD_PREP(GENMASK(2, 0), (c) >> 4))
+#define ST7571_SET_COM0_LSB(x) (FIELD_PREP(GENMASK(6, 0), (x)))
+#define ST7571_SET_COM0_MSB (0x44)
+#define ST7571_SET_COM_SCAN_DIR(d) (0xc0 | FIELD_PREP(GENMASK(3, 3), (d)))
+#define ST7571_SET_CONTRAST_LSB(c) (FIELD_PREP(GENMASK(5, 0), (c)))
+#define ST7571_SET_CONTRAST_MSB (0x81)
+#define ST7571_SET_DISPLAY_DUTY_LSB(d) (FIELD_PREP(GENMASK(7, 0), (d)))
+#define ST7571_SET_DISPLAY_DUTY_MSB (0x48)
+#define ST7571_SET_ENTIRE_DISPLAY_ON(p) (0xa4 | FIELD_PREP(GENMASK(0, 0), (p)))
+#define ST7571_SET_LCD_BIAS(b) (0x50 | FIELD_PREP(GENMASK(2, 0), (b)))
+#define ST7571_SET_MODE_LSB(m) (FIELD_PREP(GENMASK(7, 2), (m)))
+#define ST7571_SET_MODE_MSB (0x38)
+#define ST7571_SET_PAGE(p) (0xb0 | FIELD_PREP(GENMASK(3, 0), (p)))
+#define ST7571_SET_POWER(p) (0x28 | FIELD_PREP(GENMASK(2, 0), (p)))
+#define ST7571_SET_REGULATOR_REG(r) (0x20 | FIELD_PREP(GENMASK(2, 0), (r)))
+#define ST7571_SET_REVERSE(r) (0xa6 | FIELD_PREP(GENMASK(0, 0), (r)))
+#define ST7571_SET_SEG_SCAN_DIR(d) (0xa0 | FIELD_PREP(GENMASK(0, 0), (d)))
+#define ST7571_SET_START_LINE_LSB(l) (FIELD_PREP(GENMASK(6, 0), (l)))
+#define ST7571_SET_START_LINE_MSB (0x40)
+
+/* Extension command set 3 */
+#define ST7571_COMMAND_SET_3 (0x7b)
+#define ST7571_SET_COLOR_MODE(c) (0x10 | FIELD_PREP(GENMASK(0, 0), (c)))
+#define ST7571_COMMAND_SET_NORMAL (0x00)
+
+/* ST7567 commands */
+#define ST7567_SET_LCD_BIAS(m) (0xa2 | FIELD_PREP(GENMASK(0, 0), (m)))
+
+#define ST7571_PAGE_HEIGHT 8
+
+#define DRIVER_NAME "st7571"
+#define DRIVER_DESC "ST7571 DRM driver"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+static inline struct st7571_device *drm_to_st7571(struct drm_device *drm)
+{
+ return container_of(drm, struct st7571_device, drm);
+}
+
+static int st7571_send_command_list(struct st7571_device *st7571,
+ const u8 *cmd_list, size_t len)
+{
+ int ret;
+
+ for (int i = 0; i < len; i++) {
+ ret = regmap_write(st7571->regmap, ST7571_COMMAND_MODE, cmd_list[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static inline u8 st7571_transform_xy(const char *p, int x, int y, u8 bpp)
+{
+ int xrest = x % 8;
+ u8 result = 0;
+ u8 row_len = 16 * bpp;
+
+ /*
+ * Transforms an (x, y) pixel coordinate into a vertical 8-bit
+ * column from the framebuffer. It calculates the corresponding byte in the
+ * framebuffer, extracts the bit at the given x position across 8 consecutive
+ * rows, and packs those bits into a single byte.
+ *
+ * Return an 8-bit value representing a vertical column of pixels.
+ */
+ x = x / 8;
+ y = (y / 8) * 8;
+
+ for (int i = 0; i < 8; i++) {
+ int row_idx = y + i;
+ u8 byte = p[row_idx * row_len + x];
+ u8 bit = (byte >> xrest) & 1;
+
+ result |= (bit << i);
+ }
+
+ return result;
+}
+
+static int st7571_set_position(struct st7571_device *st7571, int x, int y)
+{
+ u8 cmd_list[] = {
+ ST7571_SET_COLUMN_LSB(x),
+ ST7571_SET_COLUMN_MSB(x),
+ ST7571_SET_PAGE(y / ST7571_PAGE_HEIGHT),
+ };
+
+ return st7571_send_command_list(st7571, cmd_list, ARRAY_SIZE(cmd_list));
+}
+
+static int st7571_fb_clear_screen(struct st7571_device *st7571)
+{
+ u32 npixels = st7571->ncols * round_up(st7571->nlines, ST7571_PAGE_HEIGHT) * st7571->bpp;
+ char pixelvalue = 0x00;
+
+ st7571_set_position(st7571, 0, 0);
+ for (int i = 0; i < npixels; i++)
+ regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, &pixelvalue, 1);
+
+ return 0;
+}
+
+static void st7571_prepare_buffer_monochrome(struct st7571_device *st7571,
+ const struct iosys_map *vmap,
+ struct drm_framebuffer *fb,
+ struct drm_rect *rect,
+ struct drm_format_conv_state *fmtcnv_state)
+{
+ unsigned int dst_pitch;
+ struct iosys_map dst;
+ u32 size;
+
+ switch (fb->format->format) {
+ case DRM_FORMAT_XRGB8888:
+ dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
+ iosys_map_set_vaddr(&dst, st7571->hwbuf);
+
+ drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
+ break;
+
+ case DRM_FORMAT_R1:
+ size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
+ memcpy(st7571->hwbuf, vmap->vaddr, size);
+ break;
+ }
+}
+
+static void st7571_prepare_buffer_grayscale(struct st7571_device *st7571,
+ const struct iosys_map *vmap,
+ struct drm_framebuffer *fb,
+ struct drm_rect *rect,
+ struct drm_format_conv_state *fmtcnv_state)
+{
+ u32 size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
+ unsigned int dst_pitch;
+ struct iosys_map dst;
+
+ switch (fb->format->format) {
+ case DRM_FORMAT_XRGB8888:
+ dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 4);
+ iosys_map_set_vaddr(&dst, st7571->hwbuf);
+
+ drm_fb_xrgb8888_to_gray2(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
+ break;
+
+ case DRM_FORMAT_R1:
+ size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 8;
+ memcpy(st7571->hwbuf, vmap->vaddr, size);
+ break;
+
+ case DRM_FORMAT_R2:
+ size = (rect->x2 - rect->x1) * (rect->y2 - rect->y1) / 4;
+ memcpy(st7571->hwbuf, vmap->vaddr, size);
+ break;
+ }
+}
+
+static int st7571_fb_update_rect_monochrome(struct drm_framebuffer *fb, struct drm_rect *rect)
+{
+ struct st7571_device *st7571 = drm_to_st7571(fb->dev);
+ char *row = st7571->row;
+
+ /* Align y to display page boundaries */
+ rect->y1 = round_down(rect->y1, ST7571_PAGE_HEIGHT);
+ rect->y2 = min_t(unsigned int, round_up(rect->y2, ST7571_PAGE_HEIGHT), st7571->nlines);
+
+ for (int y = rect->y1; y < rect->y2; y += ST7571_PAGE_HEIGHT) {
+ for (int x = rect->x1; x < rect->x2; x++)
+ row[x] = st7571_transform_xy(st7571->hwbuf, x, y, 1);
+
+ st7571_set_position(st7571, rect->x1, y);
+
+ /* TODO: Investige why we can't write multiple bytes at once */
+ for (int x = rect->x1; x < rect->x2; x++)
+ regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
+ }
+
+ return 0;
+}
+
+static int st7571_fb_update_rect_grayscale(struct drm_framebuffer *fb, struct drm_rect *rect)
+{
+ struct st7571_device *st7571 = drm_to_st7571(fb->dev);
+ u32 format = fb->format->format;
+ char *row = st7571->row;
+ int x1;
+ int x2;
+
+ /* Align y to display page boundaries */
+ rect->y1 = round_down(rect->y1, ST7571_PAGE_HEIGHT);
+ rect->y2 = min_t(unsigned int, round_up(rect->y2, ST7571_PAGE_HEIGHT), st7571->nlines);
+
+ switch (format) {
+ case DRM_FORMAT_R1:
+ x1 = rect->x1 * 1;
+ x2 = rect->x2 * 1;
+ break;
+ case DRM_FORMAT_R2:
+ fallthrough;
+ case DRM_FORMAT_XRGB8888:
+ x1 = rect->x1 * 2;
+ x2 = rect->x2 * 2;
+ break;
+ }
+
+ for (int y = rect->y1; y < rect->y2; y += ST7571_PAGE_HEIGHT) {
+ for (int x = x1; x < x2; x++)
+ row[x] = st7571_transform_xy(st7571->hwbuf, x, y, 2);
+
+ st7571_set_position(st7571, rect->x1, y);
+
+ /* TODO: Investige why we can't write multiple bytes at once */
+ for (int x = x1; x < x2; x++) {
+ regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
+
+ /*
+ * As the display supports grayscale, all pixels must be written as two bits
+ * even if the format is monochrome.
+ *
+ * The bit values maps to the following grayscale:
+ * 0 0 = Black
+ * 0 1 = Dark gray
+ * 1 0 = Light gray
+ * 1 1 = White
+ *
+ * For monochrome formats, write the same value twice to get
+ * either a black or white pixel.
+ */
+ if (format == DRM_FORMAT_R1)
+ regmap_bulk_write(st7571->regmap, ST7571_DATA_MODE, row + x, 1);
+ }
+ }
+
+ return 0;
+}
+
+static int st7571_connector_get_modes(struct drm_connector *conn)
+{
+ struct st7571_device *st7571 = drm_to_st7571(conn->dev);
+
+ return drm_connector_helper_get_modes_fixed(conn, &st7571->mode);
+}
+
+static const struct drm_connector_helper_funcs st7571_connector_helper_funcs = {
+ .get_modes = st7571_connector_get_modes,
+};
+
+static const struct st7571_panel_format st7571_monochrome = {
+ .prepare_buffer = st7571_prepare_buffer_monochrome,
+ .update_rect = st7571_fb_update_rect_monochrome,
+ .mode = ST7571_COLOR_MODE_BLACKWHITE,
+ .formats = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_R1,
+ },
+ .nformats = 2,
+};
+
+static const struct st7571_panel_format st7571_grayscale = {
+ .prepare_buffer = st7571_prepare_buffer_grayscale,
+ .update_rect = st7571_fb_update_rect_grayscale,
+ .mode = ST7571_COLOR_MODE_GRAY,
+ .formats = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_R1,
+ DRM_FORMAT_R2,
+ },
+ .nformats = 3,
+};
+
+static const u64 st7571_primary_plane_fmtmods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+static int st7571_primary_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_crtc *new_crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_state = NULL;
+
+ if (new_crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
+
+ return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+}
+
+static void st7571_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_device *drm = plane->dev;
+ struct drm_rect damage;
+ struct st7571_device *st7571 = drm_to_st7571(plane->dev);
+ int ret, idx;
+
+ if (!fb)
+ return; /* no framebuffer; plane is disabled */
+
+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
+ if (ret)
+ return;
+
+ if (!drm_dev_enter(drm, &idx))
+ goto out_drm_gem_fb_end_cpu_access;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ st7571->pformat->prepare_buffer(st7571,
+ &shadow_plane_state->data[0],
+ fb, &damage,
+ &shadow_plane_state->fmtcnv_state);
+
+ st7571->pformat->update_rect(fb, &damage);
+ }
+
+ drm_dev_exit(idx);
+
+out_drm_gem_fb_end_cpu_access:
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+}
+
+static void st7571_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = plane->dev;
+ struct st7571_device *st7571 = drm_to_st7571(plane->dev);
+ int idx;
+
+ if (!drm_dev_enter(drm, &idx))
+ return;
+
+ st7571_fb_clear_screen(st7571);
+ drm_dev_exit(idx);
+}
+
+static const struct drm_plane_helper_funcs st7571_primary_plane_helper_funcs = {
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
+ .atomic_check = st7571_primary_plane_helper_atomic_check,
+ .atomic_update = st7571_primary_plane_helper_atomic_update,
+ .atomic_disable = st7571_primary_plane_helper_atomic_disable,
+};
+
+static const struct drm_plane_funcs st7571_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ DRM_GEM_SHADOW_PLANE_FUNCS,
+};
+
+/*
+ * CRTC
+ */
+
+static enum drm_mode_status st7571_crtc_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct st7571_device *st7571 = drm_to_st7571(crtc->dev);
+
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &st7571->mode);
+}
+
+static const struct drm_crtc_helper_funcs st7571_crtc_helper_funcs = {
+ .atomic_check = drm_crtc_helper_atomic_check,
+ .mode_valid = st7571_crtc_mode_valid,
+};
+
+static const struct drm_crtc_funcs st7571_crtc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+/*
+ * Encoder
+ */
+
+static void st7571_encoder_atomic_enable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = encoder->dev;
+ struct st7571_device *st7571 = drm_to_st7571(drm);
+ u8 command = ST7571_DISPLAY_ON;
+ int ret;
+
+ ret = st7571->pdata->init(st7571);
+ if (ret)
+ return;
+
+ st7571_send_command_list(st7571, &command, 1);
+}
+
+static void st7571_encoder_atomic_disable(struct drm_encoder *encoder,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = encoder->dev;
+ struct st7571_device *st7571 = drm_to_st7571(drm);
+ u8 command = ST7571_DISPLAY_OFF;
+
+ st7571_send_command_list(st7571, &command, 1);
+}
+
+static const struct drm_encoder_funcs st7571_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+
+};
+
+static const struct drm_encoder_helper_funcs st7571_encoder_helper_funcs = {
+ .atomic_enable = st7571_encoder_atomic_enable,
+ .atomic_disable = st7571_encoder_atomic_disable,
+};
+
+/*
+ * Connector
+ */
+
+static const struct drm_connector_funcs st7571_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_mode_config_funcs st7571_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create_with_dirty,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static struct drm_display_mode st7571_mode(struct st7571_device *st7571)
+{
+ struct drm_display_mode mode = {
+ DRM_SIMPLE_MODE(st7571->ncols, st7571->nlines,
+ st7571->width_mm, st7571->height_mm),
+ };
+
+ return mode;
+}
+
+static int st7571_mode_config_init(struct st7571_device *st7571)
+{
+ struct drm_device *drm = &st7571->drm;
+ const struct st7571_panel_constraints *constraints = &st7571->pdata->constraints;
+ int ret;
+
+ ret = drmm_mode_config_init(drm);
+ if (ret)
+ return ret;
+
+ drm->mode_config.min_width = constraints->min_ncols;
+ drm->mode_config.min_height = constraints->min_nlines;
+ drm->mode_config.max_width = constraints->max_ncols;
+ drm->mode_config.max_height = constraints->max_nlines;
+ drm->mode_config.preferred_depth = 24;
+ drm->mode_config.funcs = &st7571_mode_config_funcs;
+
+ return 0;
+}
+
+static int st7571_plane_init(struct st7571_device *st7571,
+ const struct st7571_panel_format *pformat)
+{
+ struct drm_plane *primary_plane = &st7571->primary_plane;
+ struct drm_device *drm = &st7571->drm;
+ int ret;
+
+ ret = drm_universal_plane_init(drm, primary_plane, 0,
+ &st7571_primary_plane_funcs,
+ pformat->formats,
+ pformat->nformats,
+ st7571_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ret;
+
+ drm_plane_helper_add(primary_plane, &st7571_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ return 0;
+}
+
+static int st7571_crtc_init(struct st7571_device *st7571)
+{
+ struct drm_plane *primary_plane = &st7571->primary_plane;
+ struct drm_crtc *crtc = &st7571->crtc;
+ struct drm_device *drm = &st7571->drm;
+ int ret;
+
+ ret = drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
+ &st7571_crtc_funcs, NULL);
+ if (ret)
+ return ret;
+
+ drm_crtc_helper_add(crtc, &st7571_crtc_helper_funcs);
+
+ return 0;
+}
+
+static int st7571_encoder_init(struct st7571_device *st7571)
+{
+ struct drm_encoder *encoder = &st7571->encoder;
+ struct drm_crtc *crtc = &st7571->crtc;
+ struct drm_device *drm = &st7571->drm;
+ int ret;
+
+ ret = drm_encoder_init(drm, encoder, &st7571_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(encoder, &st7571_encoder_helper_funcs);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ return 0;
+}
+
+static int st7571_connector_init(struct st7571_device *st7571)
+{
+ struct drm_connector *connector = &st7571->connector;
+ struct drm_encoder *encoder = &st7571->encoder;
+ struct drm_device *drm = &st7571->drm;
+ int ret;
+
+ ret = drm_connector_init(drm, connector, &st7571_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ if (ret)
+ return ret;
+
+ drm_connector_helper_add(connector, &st7571_connector_helper_funcs);
+
+ return drm_connector_attach_encoder(connector, encoder);
+}
+
+DEFINE_DRM_GEM_FOPS(st7571_fops);
+
+static const struct drm_driver st7571_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+
+ .fops = &st7571_fops,
+ DRM_GEM_SHMEM_DRIVER_OPS,
+ DRM_FBDEV_SHMEM_DRIVER_OPS,
+};
+
+static int st7571_validate_parameters(struct st7571_device *st7571)
+{
+ struct device *dev = st7571->dev;
+ const struct st7571_panel_constraints *constraints = &st7571->pdata->constraints;
+
+ if (st7571->width_mm == 0) {
+ dev_err(dev, "Invalid panel width\n");
+ return -EINVAL;
+ }
+
+ if (st7571->height_mm == 0) {
+ dev_err(dev, "Invalid panel height\n");
+ return -EINVAL;
+ }
+
+ if (st7571->nlines < constraints->min_nlines ||
+ st7571->nlines > constraints->max_nlines) {
+ dev_err(dev, "Invalid timing configuration.\n");
+ return -EINVAL;
+ }
+
+ if (st7571->startline + st7571->nlines > constraints->max_nlines) {
+ dev_err(dev, "Invalid timing configuration.\n");
+ return -EINVAL;
+ }
+
+ if (st7571->ncols < constraints->min_ncols ||
+ st7571->ncols > constraints->max_ncols) {
+ dev_err(dev, "Invalid timing configuration.\n");
+ return -EINVAL;
+ }
+
+ if (st7571->grayscale && !constraints->support_grayscale) {
+ dev_err(dev, "Grayscale not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int st7567_parse_dt(struct st7571_device *st7567)
+{
+ struct device *dev = st7567->dev;
+ struct device_node *np = dev->of_node;
+ struct display_timing dt;
+ int ret;
+
+ ret = of_get_display_timing(np, "panel-timing", &dt);
+ if (ret) {
+ dev_err(dev, "Failed to get display timing from DT\n");
+ return ret;
+ }
+
+ of_property_read_u32(np, "width-mm", &st7567->width_mm);
+ of_property_read_u32(np, "height-mm", &st7567->height_mm);
+ st7567->inverted = of_property_read_bool(np, "sitronix,inverted");
+
+ st7567->pformat = &st7571_monochrome;
+ st7567->bpp = 1;
+
+ st7567->startline = dt.vfront_porch.typ;
+ st7567->nlines = dt.vactive.typ;
+ st7567->ncols = dt.hactive.typ;
+
+ return 0;
+}
+
+static int st7571_parse_dt(struct st7571_device *st7571)
+{
+ struct device *dev = st7571->dev;
+ struct device_node *np = dev->of_node;
+ struct display_timing dt;
+ int ret;
+
+ ret = of_get_display_timing(np, "panel-timing", &dt);
+ if (ret) {
+ dev_err(dev, "Failed to get display timing from DT\n");
+ return ret;
+ }
+
+ of_property_read_u32(np, "width-mm", &st7571->width_mm);
+ of_property_read_u32(np, "height-mm", &st7571->height_mm);
+ st7571->grayscale = of_property_read_bool(np, "sitronix,grayscale");
+ st7571->inverted = of_property_read_bool(np, "sitronix,inverted");
+
+ if (st7571->grayscale) {
+ st7571->pformat = &st7571_grayscale;
+ st7571->bpp = 2;
+ } else {
+ st7571->pformat = &st7571_monochrome;
+ st7571->bpp = 1;
+ }
+
+ st7571->startline = dt.vfront_porch.typ;
+ st7571->nlines = dt.vactive.typ;
+ st7571->ncols = dt.hactive.typ;
+
+ st7571->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(st7571->reset))
+ return dev_err_probe(dev, PTR_ERR(st7571->reset),
+ "Failed to get reset gpio\n");
+
+ return 0;
+}
+
+static void st7571_reset(struct st7571_device *st7571)
+{
+ gpiod_set_value_cansleep(st7571->reset, 1);
+ fsleep(20);
+ gpiod_set_value_cansleep(st7571->reset, 0);
+}
+
+static int st7567_lcd_init(struct st7571_device *st7567)
+{
+ /*
+ * Most of the initialization sequence is taken directly from the
+ * referential initial code in the ST7567 datasheet.
+ */
+ u8 commands[] = {
+ ST7571_DISPLAY_OFF,
+
+ ST7567_SET_LCD_BIAS(1),
+
+ ST7571_SET_SEG_SCAN_DIR(0),
+ ST7571_SET_COM_SCAN_DIR(1),
+
+ ST7571_SET_REGULATOR_REG(4),
+ ST7571_SET_CONTRAST_MSB,
+ ST7571_SET_CONTRAST_LSB(0x20),
+
+ ST7571_SET_START_LINE_MSB,
+ ST7571_SET_START_LINE_LSB(st7567->startline),
+
+ ST7571_SET_POWER(0x4), /* Power Control, VC: ON, VR: OFF, VF: OFF */
+ ST7571_SET_POWER(0x6), /* Power Control, VC: ON, VR: ON, VF: OFF */
+ ST7571_SET_POWER(0x7), /* Power Control, VC: ON, VR: ON, VF: ON */
+
+ ST7571_SET_REVERSE(st7567->inverted ? 1 : 0),
+ ST7571_SET_ENTIRE_DISPLAY_ON(0),
+ };
+
+ return st7571_send_command_list(st7567, commands, ARRAY_SIZE(commands));
+}
+
+static int st7571_lcd_init(struct st7571_device *st7571)
+{
+ /*
+ * Most of the initialization sequence is taken directly from the
+ * referential initial code in the ST7571 datasheet.
+ */
+ u8 commands[] = {
+ ST7571_DISPLAY_OFF,
+
+ ST7571_SET_MODE_MSB,
+ ST7571_SET_MODE_LSB(0x2e),
+
+ ST7571_SET_SEG_SCAN_DIR(0),
+ ST7571_SET_COM_SCAN_DIR(1),
+
+ ST7571_SET_COM0_MSB,
+ ST7571_SET_COM0_LSB(0x00),
+
+ ST7571_SET_START_LINE_MSB,
+ ST7571_SET_START_LINE_LSB(st7571->startline),
+
+ ST7571_OSC_ON,
+ ST7571_SET_REGULATOR_REG(5),
+ ST7571_SET_CONTRAST_MSB,
+ ST7571_SET_CONTRAST_LSB(0x33),
+ ST7571_SET_LCD_BIAS(0x04),
+ ST7571_SET_DISPLAY_DUTY_MSB,
+ ST7571_SET_DISPLAY_DUTY_LSB(st7571->nlines),
+
+ ST7571_SET_POWER(0x4), /* Power Control, VC: ON, VR: OFF, VF: OFF */
+ ST7571_SET_POWER(0x6), /* Power Control, VC: ON, VR: ON, VF: OFF */
+ ST7571_SET_POWER(0x7), /* Power Control, VC: ON, VR: ON, VF: ON */
+
+ ST7571_COMMAND_SET_3,
+ ST7571_SET_COLOR_MODE(st7571->pformat->mode),
+ ST7571_COMMAND_SET_NORMAL,
+
+ ST7571_SET_REVERSE(st7571->inverted ? 1 : 0),
+ ST7571_SET_ENTIRE_DISPLAY_ON(0),
+ };
+
+ /* Perform a reset before initializing the controller */
+ st7571_reset(st7571);
+
+ return st7571_send_command_list(st7571, commands, ARRAY_SIZE(commands));
+}
+
+struct st7571_device *st7571_probe(struct device *dev,
+ struct regmap *regmap)
+{
+ struct st7571_device *st7571;
+ struct drm_device *drm;
+ int ret;
+
+ st7571 = devm_drm_dev_alloc(dev, &st7571_driver,
+ struct st7571_device, drm);
+ if (IS_ERR(st7571))
+ return st7571;
+
+ drm = &st7571->drm;
+ st7571->dev = dev;
+ st7571->pdata = device_get_match_data(st7571->dev);
+
+ ret = st7571->pdata->parse_dt(st7571);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = st7571_validate_parameters(st7571);
+ if (ret)
+ return ERR_PTR(ret);
+
+ st7571->mode = st7571_mode(st7571);
+ st7571->regmap = regmap;
+
+ st7571->hwbuf = devm_kzalloc(st7571->dev,
+ (st7571->nlines * st7571->ncols * st7571->bpp) / 8,
+ GFP_KERNEL);
+ if (!st7571->hwbuf)
+ return ERR_PTR(-ENOMEM);
+
+ st7571->row = devm_kzalloc(st7571->dev,
+ (st7571->ncols * st7571->bpp),
+ GFP_KERNEL);
+ if (!st7571->row)
+ return ERR_PTR(-ENOMEM);
+
+ ret = st7571_mode_config_init(st7571);
+ if (ret) {
+ dev_err(st7571->dev, "Failed to initialize mode config\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = st7571_plane_init(st7571, st7571->pformat);
+ if (ret) {
+ dev_err(st7571->dev, "Failed to initialize primary plane\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = st7571_crtc_init(st7571);
+ if (ret < 0) {
+ dev_err(st7571->dev, "Failed to initialize CRTC\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = st7571_encoder_init(st7571);
+ if (ret < 0) {
+ dev_err(st7571->dev, "Failed to initialize encoder\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = st7571_connector_init(st7571);
+ if (ret < 0) {
+ dev_err(st7571->dev, "Failed to initialize connector\n");
+ return ERR_PTR(ret);
+ }
+
+ drm_mode_config_reset(drm);
+
+ ret = drm_dev_register(drm, 0);
+ if (ret) {
+ dev_err(st7571->dev, "Failed to register DRM device\n");
+ return ERR_PTR(ret);
+ }
+
+ drm_client_setup(drm, NULL);
+ return st7571;
+}
+EXPORT_SYMBOL_GPL(st7571_probe);
+
+void st7571_remove(struct st7571_device *st7571)
+{
+ drm_dev_unplug(&st7571->drm);
+}
+EXPORT_SYMBOL_GPL(st7571_remove);
+
+const struct st7571_panel_data st7567_config = {
+ .init = st7567_lcd_init,
+ .parse_dt = st7567_parse_dt,
+ .constraints = {
+ .min_nlines = 1,
+ .max_nlines = 64,
+ .min_ncols = 128,
+ .max_ncols = 128,
+ .support_grayscale = false,
+ },
+};
+EXPORT_SYMBOL_NS_GPL(st7567_config, "DRM_ST7571");
+
+const struct st7571_panel_data st7571_config = {
+ .init = st7571_lcd_init,
+ .parse_dt = st7571_parse_dt,
+ .constraints = {
+ .min_nlines = 1,
+ .max_nlines = 128,
+ .min_ncols = 128,
+ .max_ncols = 128,
+ .support_grayscale = true,
+ },
+};
+EXPORT_SYMBOL_NS_GPL(st7571_config, "DRM_ST7571");
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("DRM Driver for Sitronix ST7571 LCD controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sitronix/st7571.h b/drivers/gpu/drm/sitronix/st7571.h
new file mode 100644
index 000000000000..af264f2e2ea4
--- /dev/null
+++ b/drivers/gpu/drm/sitronix/st7571.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Header file for:
+ * Driver for Sitronix ST7571, a 4 level gray scale dot matrix LCD controller
+ *
+ * Copyright (C) 2025 Marcus Folkesson <marcus.folkesson@gmail.com>
+ */
+
+#ifndef __ST7571_H__
+#define __ST7571_H__
+
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_format_helper.h>
+
+#include <linux/regmap.h>
+
+enum st7571_color_mode {
+ ST7571_COLOR_MODE_GRAY = 0,
+ ST7571_COLOR_MODE_BLACKWHITE = 1,
+};
+
+struct st7571_device;
+
+struct st7571_panel_constraints {
+ u32 min_nlines;
+ u32 max_nlines;
+ u32 min_ncols;
+ u32 max_ncols;
+ bool support_grayscale;
+};
+
+struct st7571_panel_data {
+ int (*init)(struct st7571_device *st7571);
+ int (*parse_dt)(struct st7571_device *st7571);
+ struct st7571_panel_constraints constraints;
+};
+
+struct st7571_panel_format {
+ void (*prepare_buffer)(struct st7571_device *st7571,
+ const struct iosys_map *vmap,
+ struct drm_framebuffer *fb,
+ struct drm_rect *rect,
+ struct drm_format_conv_state *fmtcnv_state);
+ int (*update_rect)(struct drm_framebuffer *fb, struct drm_rect *rect);
+ enum st7571_color_mode mode;
+ const u8 nformats;
+ const u32 formats[];
+};
+
+struct st7571_device {
+ struct drm_device drm;
+ struct device *dev;
+
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+
+ struct drm_display_mode mode;
+
+ const struct st7571_panel_format *pformat;
+ const struct st7571_panel_data *pdata;
+ struct gpio_desc *reset;
+ struct regmap *regmap;
+
+ bool grayscale;
+ bool inverted;
+ u32 height_mm;
+ u32 width_mm;
+ u32 startline;
+ u32 nlines;
+ u32 ncols;
+ u32 bpp;
+
+ /* Intermediate buffer in LCD friendly format */
+ u8 *hwbuf;
+
+ /* Row of (transformed) pixels ready to be written to the display */
+ u8 *row;
+};
+
+extern const struct st7571_panel_data st7567_config;
+extern const struct st7571_panel_data st7571_config;
+
+struct st7571_device *st7571_probe(struct device *dev, struct regmap *regmap);
+void st7571_remove(struct st7571_device *st7571);
+
+#endif /* __ST7571_H__ */
diff --git a/drivers/gpu/drm/sitronix/st7920.c b/drivers/gpu/drm/sitronix/st7920.c
new file mode 100644
index 000000000000..f35a157fdad8
--- /dev/null
+++ b/drivers/gpu/drm/sitronix/st7920.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DRM driver for Sitronix ST7920 LCD displays
+ *
+ * Copyright 2025 Iker Pedrosa <ikerpedrosam@gmail.com>
+ *
+ */
+
+#include <linux/bitrev.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_shmem.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#define DRIVER_NAME "sitronix_st7920"
+#define DRIVER_DESC "DRM driver for Sitronix ST7920 LCD displays"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+/* Display organization */
+#define ST7920_PITCH 16
+#define ST7920_SCANLINES 64
+#define BYTES_IN_DISPLAY (ST7920_PITCH * ST7920_SCANLINES)
+#define BYTES_IN_SEGMENT 2
+#define PIXELS_PER_SEGMENT (BYTES_IN_SEGMENT * 8)
+#define ST7920_DEFAULT_WIDTH 128
+#define ST7920_DEFAULT_HEIGHT 64
+
+/* Sync sequence */
+#define SYNC_BITS 0xF8
+#define RW_HIGH 0x04
+#define RS_HIGH 0x02
+
+/* Commands */
+#define SET_DISPLAY_ON 0x0C
+#define SET_DISPLAY_OFF 0x08
+#define SET_DISPLAY_CLEAR 0x01
+#define SET_BASIC_INSTRUCTION_SET 0x30
+#define SET_EXT_INSTRUCTION_SET 0x34
+#define SET_GRAPHICS_DISPLAY 0x36
+#define SET_GDRAM_ADDRESS 0x80
+#define SET_GDRAM_DATA 0xFF /* Driver internal command */
+
+/* Masks */
+#define HIGH_DATA_MASK 0xF0
+#define LOW_DATA_MASK 0x0F
+#define TOP_VERTICAL_ADDRESS 0x80
+#define BOTTOM_VERTICAL_ADDRESS 0x60
+#define TOP_HORIZONTAL_ADDRESS 0x00
+#define BOTTOM_HORIZONTAL_ADDRESS 0x80
+
+#define CMD_SIZE 35
+
+struct spi7920_error {
+ int errno;
+};
+
+struct st7920_device {
+ struct drm_device drm;
+ struct drm_display_mode mode;
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+ struct spi_device *spi;
+
+ struct regmap *regmap;
+
+ struct gpio_desc *reset_gpio;
+
+ u32 height;
+ u32 width;
+};
+
+struct st7920_plane_state {
+ struct drm_shadow_plane_state base;
+ /* Intermediate buffer to convert pixels from XRGB8888 to HW format */
+ u8 *buffer;
+};
+
+struct st7920_crtc_state {
+ struct drm_crtc_state base;
+ /* Buffer to store pixels in HW format and written to the panel */
+ u8 *data_array;
+};
+
+static inline struct st7920_plane_state *to_st7920_plane_state(struct drm_plane_state *state)
+{
+ return container_of(state, struct st7920_plane_state, base.base);
+}
+
+static inline struct st7920_crtc_state *to_st7920_crtc_state(struct drm_crtc_state *state)
+{
+ return container_of(state, struct st7920_crtc_state, base);
+}
+
+static inline struct st7920_device *drm_to_st7920(struct drm_device *drm)
+{
+ return container_of(drm, struct st7920_device, drm);
+}
+
+static int st7920_store_gdram_address(const void *data, u8 *reg)
+{
+ const u8 y_addr = *(const u8 *)data;
+ bool bottom_screen = (y_addr >= 32);
+ int i = 0;
+
+ reg[i++] = SYNC_BITS;
+ /* Set vertical address */
+ if (!bottom_screen)
+ reg[i++] = TOP_VERTICAL_ADDRESS + (*(uint8_t *)data & HIGH_DATA_MASK);
+ else
+ reg[i++] = BOTTOM_VERTICAL_ADDRESS + (*(uint8_t *)data & HIGH_DATA_MASK);
+
+ reg[i++] = *(uint8_t *)data << 4;
+ /* Set horizontal address */
+ reg[i++] = SET_GDRAM_ADDRESS;
+ if (!bottom_screen)
+ reg[i++] = TOP_HORIZONTAL_ADDRESS;
+ else
+ reg[i++] = BOTTOM_HORIZONTAL_ADDRESS;
+
+ return i;
+}
+
+static int st7920_store_gdram_data(const void *data, u8 *reg)
+{
+ const u8 *line_data = data;
+ int i = 0, j = 0;
+
+ reg[i++] = SYNC_BITS | RS_HIGH;
+
+ for (j = 0; j < 16; j++) {
+ reg[i++] = line_data[j] & 0xF0;
+ reg[i++] = (line_data[j] << 4) & 0xF0;
+ }
+
+ return i;
+}
+
+static int st7920_store_others(int cmd, const void *data, u8 *reg)
+{
+ int i = 0;
+
+ reg[i++] = SYNC_BITS;
+ reg[i++] = cmd & HIGH_DATA_MASK;
+ reg[i++] = (cmd & LOW_DATA_MASK) << 4;
+
+ return i;
+}
+
+static void st7920_spi_write(struct spi_device *spi, int cmd, const void *data,
+ int delay_us, struct spi7920_error *err)
+{
+ u8 reg[CMD_SIZE] = {0};
+ int size = 0;
+ int ret;
+
+ if (err->errno)
+ return;
+
+ /*
+ * First the sync bits are sent: 11111WS0.
+ * Where W is the read/write (RW) bit and S is the register/data (RS) bit.
+ * Then, every 8 bits instruction/data will be separated into 2 groups.
+ * Higher 4 bits (DB7~DB4) will be placed in the first section followed by
+ * 4 '0's. And lower 4 bits (DB3~DB0) will be placed in the second section
+ * followed by 4 '0's.
+ */
+ if (cmd == SET_GDRAM_ADDRESS)
+ size = st7920_store_gdram_address(data, reg);
+ else if (cmd == SET_GDRAM_DATA)
+ size = st7920_store_gdram_data(data, reg);
+ else
+ size = st7920_store_others(cmd, data, reg);
+
+ ret = spi_write(spi, reg, size);
+ if (ret) {
+ err->errno = ret;
+ return;
+ }
+
+ if (delay_us)
+ udelay(delay_us);
+}
+
+static const struct regmap_config st7920_spi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct of_device_id st7920_of_match[] = {
+ /* st7920 family */
+ {
+ .compatible = "sitronix,st7920",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, st7920_of_match);
+
+/*
+ * The SPI core always reports a MODALIAS uevent of the form "spi:<dev>", even
+ * if the device was registered via OF. This means that the module will not be
+ * auto loaded, unless it contains an alias that matches the MODALIAS reported.
+ *
+ * To workaround this issue, add a SPI device ID table. Even when this should
+ * not be needed for this driver to match the registered SPI devices.
+ */
+static const struct spi_device_id st7920_spi_id[] = {
+ /* st7920 family */
+ { "st7920", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, st7920_spi_id);
+
+static void st7920_power_on(struct st7920_device *st7920,
+ struct spi7920_error *err)
+{
+ st7920_spi_write(st7920->spi, SET_DISPLAY_ON, NULL, 72, err);
+}
+
+static void st7920_power_off(struct st7920_device *st7920,
+ struct spi7920_error *err)
+{
+ st7920_spi_write(st7920->spi, SET_DISPLAY_CLEAR, NULL, 1600, err);
+ st7920_spi_write(st7920->spi, SET_DISPLAY_OFF, NULL, 72, err);
+}
+
+static void st7920_hw_reset(struct st7920_device *st7920)
+{
+ if (!st7920->reset_gpio)
+ return;
+
+ gpiod_set_value_cansleep(st7920->reset_gpio, 1);
+ usleep_range(15, 20);
+ gpiod_set_value_cansleep(st7920->reset_gpio, 0);
+ msleep(40);
+}
+
+static int st7920_init(struct st7920_device *st7920)
+{
+ struct spi7920_error err = {0};
+
+ st7920_spi_write(st7920->spi, SET_BASIC_INSTRUCTION_SET, NULL, 72, &err);
+ st7920_power_on(st7920, &err);
+ st7920_spi_write(st7920->spi, SET_GRAPHICS_DISPLAY, NULL, 72, &err);
+ st7920_spi_write(st7920->spi, SET_DISPLAY_CLEAR, NULL, 1600, &err);
+
+ return err.errno;
+}
+
+static int st7920_update_rect(struct st7920_device *st7920,
+ struct drm_rect *rect, u8 *buf,
+ u8 *data_array)
+{
+ struct spi7920_error err = {0};
+ u32 array_idx = 0;
+ int i, j;
+
+ /*
+ * The screen is divided in 64(Y)x8(X) segments and each segment is
+ * further divided in 2 bytes (D15~D0).
+ *
+ * Segment 0x0 is in the top-right corner, while segment 63x15 is in the
+ * bottom-left. They would be displayed in the screen in the following way:
+ * 0x0 0x1 0x2 ... 0x15
+ * 1x0 1x1 1x2 ... 1x15
+ * ...
+ * 63x0 63x1 63x2 ... 63x15
+ *
+ * The data in each byte is big endian.
+ */
+
+ for (i = 0; i < ST7920_SCANLINES; i++) {
+ u8 *line_start = buf + (i * ST7920_PITCH);
+ u8 line_buffer[ST7920_PITCH];
+
+ for (j = 0; j < ST7920_PITCH; j++) {
+ line_buffer[j] = bitrev8(line_start[j]);
+ data_array[array_idx++] = line_buffer[j];
+ }
+
+ st7920_spi_write(st7920->spi, SET_GDRAM_ADDRESS, &i, 72, &err);
+ st7920_spi_write(st7920->spi, SET_GDRAM_DATA, line_buffer, 72, &err);
+ }
+
+ return err.errno;
+}
+
+static void st7920_clear_screen(struct st7920_device *st7920, u8 *data_array)
+{
+ struct spi7920_error err = {0};
+
+ memset(data_array, 0, BYTES_IN_DISPLAY);
+
+ st7920_spi_write(st7920->spi, SET_DISPLAY_CLEAR, NULL, 1600, &err);
+}
+
+static int st7920_fb_blit_rect(struct drm_framebuffer *fb,
+ const struct iosys_map *vmap,
+ struct drm_rect *rect,
+ u8 *buf, u8 *data_array,
+ struct drm_format_conv_state *fmtcnv_state)
+{
+ struct st7920_device *st7920 = drm_to_st7920(fb->dev);
+ struct iosys_map dst;
+ unsigned int dst_pitch;
+ int ret;
+
+ /* Align y to display page boundaries */
+ rect->y1 = round_down(rect->y1, PIXELS_PER_SEGMENT);
+ rect->y2 = min_t(unsigned int, round_up(rect->y2, PIXELS_PER_SEGMENT), st7920->height);
+
+ dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
+
+ iosys_map_set_vaddr(&dst, buf);
+ drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
+
+ ret = st7920_update_rect(st7920, rect, buf, data_array);
+
+ return ret;
+}
+
+static int st7920_primary_plane_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = plane->dev;
+ struct st7920_device *st7920 = drm_to_st7920(drm);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct st7920_plane_state *st7920_state = to_st7920_plane_state(plane_state);
+ struct drm_shadow_plane_state *shadow_plane_state = &st7920_state->base;
+ struct drm_crtc *crtc = plane_state->crtc;
+ struct drm_crtc_state *crtc_state = NULL;
+ const struct drm_format_info *fi;
+ unsigned int pitch;
+ int ret;
+
+ if (crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+ ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+ if (ret)
+ return ret;
+ else if (!plane_state->visible)
+ return 0;
+
+ fi = drm_format_info(DRM_FORMAT_R1);
+ if (!fi)
+ return -EINVAL;
+
+ pitch = drm_format_info_min_pitch(fi, 0, st7920->width);
+
+ if (plane_state->fb->format != fi) {
+ void *buf;
+
+ /* format conversion necessary; reserve buffer */
+ buf = drm_format_conv_state_reserve(&shadow_plane_state->fmtcnv_state,
+ pitch, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ st7920_state->buffer = kcalloc(pitch, st7920->height, GFP_KERNEL);
+ if (!st7920_state->buffer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void st7920_primary_plane_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
+ struct st7920_crtc_state *st7920_crtc_state = to_st7920_crtc_state(crtc_state);
+ struct st7920_plane_state *st7920_plane_state = to_st7920_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_device *drm = plane->dev;
+ struct drm_rect dst_clip;
+ struct drm_rect damage;
+ int idx;
+ int ret;
+
+ if (!drm_dev_enter(drm, &idx))
+ return;
+
+ if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ dst_clip = plane_state->dst;
+
+ if (!drm_rect_intersect(&dst_clip, &damage))
+ continue;
+
+ ret = st7920_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,
+ st7920_plane_state->buffer,
+ st7920_crtc_state->data_array,
+ &shadow_plane_state->fmtcnv_state);
+ if (ret)
+ drm_err_once(plane->dev, "Failed to write to device: %d.\n", ret);
+ }
+
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+ }
+
+ drm_dev_exit(idx);
+}
+
+static void st7920_primary_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = plane->dev;
+ struct st7920_device *st7920 = drm_to_st7920(drm);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_crtc_state *crtc_state;
+ struct st7920_crtc_state *st7920_crtc_state;
+ int idx;
+
+ if (!plane_state->crtc)
+ return;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
+ st7920_crtc_state = to_st7920_crtc_state(crtc_state);
+
+ if (!drm_dev_enter(drm, &idx))
+ return;
+
+ st7920_clear_screen(st7920, st7920_crtc_state->data_array);
+
+ drm_dev_exit(idx);
+}
+
+/* Called during init to allocate the plane's atomic state. */
+static void st7920_primary_plane_reset(struct drm_plane *plane)
+{
+ struct st7920_plane_state *st7920_state;
+
+ drm_WARN_ON_ONCE(plane->dev, plane->state);
+
+ st7920_state = kzalloc(sizeof(*st7920_state), GFP_KERNEL);
+ if (!st7920_state)
+ return;
+
+ __drm_gem_reset_shadow_plane(plane, &st7920_state->base);
+}
+
+static struct drm_plane_state *st7920_primary_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct drm_shadow_plane_state *new_shadow_plane_state;
+ struct st7920_plane_state *st7920_state;
+
+ if (drm_WARN_ON_ONCE(plane->dev, !plane->state))
+ return NULL;
+
+ st7920_state = kzalloc(sizeof(*st7920_state), GFP_KERNEL);
+ if (!st7920_state)
+ return NULL;
+
+ new_shadow_plane_state = &st7920_state->base;
+
+ __drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state);
+
+ return &new_shadow_plane_state->base;
+}
+
+static void st7920_primary_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct st7920_plane_state *st7920_state = to_st7920_plane_state(state);
+
+ kfree(st7920_state->buffer);
+
+ __drm_gem_destroy_shadow_plane_state(&st7920_state->base);
+
+ kfree(st7920_state);
+}
+
+static const struct drm_plane_helper_funcs st7920_primary_plane_helper_funcs = {
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
+ .atomic_check = st7920_primary_plane_atomic_check,
+ .atomic_update = st7920_primary_plane_atomic_update,
+ .atomic_disable = st7920_primary_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs st7920_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .reset = st7920_primary_plane_reset,
+ .atomic_duplicate_state = st7920_primary_plane_duplicate_state,
+ .atomic_destroy_state = st7920_primary_plane_destroy_state,
+ .destroy = drm_plane_cleanup,
+};
+
+static enum drm_mode_status st7920_crtc_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct st7920_device *st7920 = drm_to_st7920(crtc->dev);
+
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &st7920->mode);
+}
+
+static int st7920_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ struct st7920_crtc_state *st7920_state = to_st7920_crtc_state(crtc_state);
+ int ret;
+
+ ret = drm_crtc_helper_atomic_check(crtc, state);
+ if (ret)
+ return ret;
+
+ st7920_state->data_array = kmalloc(BYTES_IN_DISPLAY, GFP_KERNEL);
+ if (!st7920_state->data_array)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void st7920_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = crtc->dev;
+ struct st7920_device *st7920 = drm_to_st7920(drm);
+ int idx;
+ int ret;
+
+ if (!drm_dev_enter(drm, &idx))
+ return;
+
+ st7920_hw_reset(st7920);
+
+ ret = st7920_init(st7920);
+ if (ret)
+ drm_err(drm, "Failed to init hardware: %d\n", ret);
+
+ drm_dev_exit(idx);
+}
+
+static void st7920_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct spi7920_error err = {0};
+ struct drm_device *drm = crtc->dev;
+ struct st7920_device *st7920 = drm_to_st7920(drm);
+ int idx;
+
+ drm_dev_enter(drm, &idx);
+
+ st7920_power_off(st7920, &err);
+
+ drm_dev_exit(idx);
+}
+
+/* Called during init to allocate the CRTC's atomic state. */
+static void st7920_crtc_reset(struct drm_crtc *crtc)
+{
+ struct st7920_crtc_state *st7920_state;
+
+ drm_WARN_ON_ONCE(crtc->dev, crtc->state);
+
+ st7920_state = kzalloc(sizeof(*st7920_state), GFP_KERNEL);
+ if (!st7920_state)
+ return;
+
+ __drm_atomic_helper_crtc_reset(crtc, &st7920_state->base);
+}
+
+static struct drm_crtc_state *st7920_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct st7920_crtc_state *st7920_state;
+
+ if (drm_WARN_ON_ONCE(crtc->dev, !crtc->state))
+ return NULL;
+
+ st7920_state = kzalloc(sizeof(*st7920_state), GFP_KERNEL);
+ if (!st7920_state)
+ return NULL;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &st7920_state->base);
+
+ return &st7920_state->base;
+}
+
+static void st7920_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct st7920_crtc_state *st7920_state = to_st7920_crtc_state(state);
+
+ kfree(st7920_state->data_array);
+
+ __drm_atomic_helper_crtc_destroy_state(state);
+
+ kfree(st7920_state);
+}
+
+/*
+ * The CRTC is always enabled. Screen updates are performed by
+ * the primary plane's atomic_update function. Disabling clears
+ * the screen in the primary plane's atomic_disable function.
+ */
+static const struct drm_crtc_helper_funcs st7920_crtc_helper_funcs = {
+ .mode_valid = st7920_crtc_mode_valid,
+ .atomic_check = st7920_crtc_atomic_check,
+ .atomic_enable = st7920_crtc_atomic_enable,
+ .atomic_disable = st7920_crtc_atomic_disable,
+};
+
+static const struct drm_crtc_funcs st7920_crtc_funcs = {
+ .reset = st7920_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = st7920_crtc_duplicate_state,
+ .atomic_destroy_state = st7920_crtc_destroy_state,
+};
+
+static const struct drm_encoder_funcs st7920_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int st7920_connector_get_modes(struct drm_connector *connector)
+{
+ struct st7920_device *st7920 = drm_to_st7920(connector->dev);
+
+ return drm_connector_helper_get_modes_fixed(connector, &st7920->mode);
+}
+
+static const struct drm_connector_helper_funcs st7920_connector_helper_funcs = {
+ .get_modes = st7920_connector_get_modes,
+};
+
+static const struct drm_connector_funcs st7920_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_mode_config_funcs st7920_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create_with_dirty,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static const uint32_t st7920_formats[] = {
+ DRM_FORMAT_XRGB8888,
+};
+
+DEFINE_DRM_GEM_FOPS(st7920_fops);
+
+static const struct drm_driver st7920_drm_driver = {
+ DRM_GEM_SHMEM_DRIVER_OPS,
+ DRM_FBDEV_SHMEM_DRIVER_OPS,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+ .fops = &st7920_fops,
+};
+
+static int st7920_init_modeset(struct st7920_device *st7920)
+{
+ struct drm_display_mode *mode = &st7920->mode;
+ struct drm_device *drm = &st7920->drm;
+ unsigned long max_width, max_height;
+ struct drm_plane *primary_plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int ret;
+
+ /*
+ * Modesetting
+ */
+
+ ret = drmm_mode_config_init(drm);
+ if (ret) {
+ drm_err(drm, "DRM mode config init failed: %d\n", ret);
+ return ret;
+ }
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ mode->clock = 30;
+ mode->hdisplay = st7920->width;
+ mode->htotal = st7920->width;
+ mode->hsync_start = st7920->width;
+ mode->hsync_end = st7920->width;
+ mode->vdisplay = st7920->height;
+ mode->vtotal = st7920->height;
+ mode->vsync_start = st7920->height;
+ mode->vsync_end = st7920->height;
+ mode->width_mm = 27;
+ mode->height_mm = 27;
+
+ max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
+ max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
+
+ drm->mode_config.min_width = mode->hdisplay;
+ drm->mode_config.max_width = max_width;
+ drm->mode_config.min_height = mode->vdisplay;
+ drm->mode_config.max_height = max_height;
+ drm->mode_config.preferred_depth = 24;
+ drm->mode_config.funcs = &st7920_mode_config_funcs;
+
+ /* Primary plane */
+
+ primary_plane = &st7920->primary_plane;
+ ret = drm_universal_plane_init(drm, primary_plane, 0, &st7920_primary_plane_funcs,
+ st7920_formats, ARRAY_SIZE(st7920_formats),
+ NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(drm, "DRM primary plane init failed: %d\n", ret);
+ return ret;
+ }
+
+ drm_plane_helper_add(primary_plane, &st7920_primary_plane_helper_funcs);
+
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ /* CRTC */
+
+ crtc = &st7920->crtc;
+ ret = drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
+ &st7920_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(drm, "DRM crtc init failed: %d\n", ret);
+ return ret;
+ }
+
+ drm_crtc_helper_add(crtc, &st7920_crtc_helper_funcs);
+
+ /* Encoder */
+
+ encoder = &st7920->encoder;
+ ret = drm_encoder_init(drm, encoder, &st7920_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+ if (ret) {
+ drm_err(drm, "DRM encoder init failed: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ /* Connector */
+
+ connector = &st7920->connector;
+ ret = drm_connector_init(drm, connector, &st7920_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ if (ret) {
+ drm_err(drm, "DRM connector init failed: %d\n", ret);
+ return ret;
+ }
+
+ drm_connector_helper_add(connector, &st7920_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(drm, "DRM attach connector to encoder failed: %d\n", ret);
+ return ret;
+ }
+
+ drm_mode_config_reset(drm);
+
+ return 0;
+}
+
+static int st7920_probe(struct spi_device *spi)
+{
+ struct st7920_device *st7920;
+ struct regmap *regmap;
+ struct device *dev = &spi->dev;
+ struct drm_device *drm;
+ int ret;
+
+ regmap = devm_regmap_init_spi(spi, &st7920_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ st7920 = devm_drm_dev_alloc(dev, &st7920_drm_driver,
+ struct st7920_device, drm);
+ if (IS_ERR(st7920))
+ return PTR_ERR(st7920);
+
+ drm = &st7920->drm;
+
+ st7920->drm.dev = dev;
+ st7920->regmap = regmap;
+ st7920->spi = spi;
+ st7920->width = ST7920_DEFAULT_WIDTH;
+ st7920->height = ST7920_DEFAULT_HEIGHT;
+
+ st7920->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(st7920->reset_gpio)) {
+ ret = PTR_ERR(st7920->reset_gpio);
+ return dev_err_probe(dev, ret, "Unable to retrieve reset GPIO\n");
+ }
+
+ spi_set_drvdata(spi, st7920);
+
+ ret = st7920_init_modeset(st7920);
+ if (ret)
+ return ret;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "DRM device register failed\n");
+
+ drm_client_setup(drm, NULL);
+
+ return 0;
+}
+
+static void st7920_remove(struct spi_device *spi)
+{
+ struct st7920_device *st7920 = spi_get_drvdata(spi);
+
+ drm_dev_unplug(&st7920->drm);
+ drm_atomic_helper_shutdown(&st7920->drm);
+}
+
+static void st7920_shutdown(struct spi_device *spi)
+{
+ struct st7920_device *st7920 = spi_get_drvdata(spi);
+
+ drm_atomic_helper_shutdown(&st7920->drm);
+}
+
+static struct spi_driver st7920_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = st7920_of_match,
+ },
+ .id_table = st7920_spi_id,
+ .probe = st7920_probe,
+ .remove = st7920_remove,
+ .shutdown = st7920_shutdown,
+};
+module_spi_driver(st7920_spi_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Iker Pedrosa <ipedrosam@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_atomic_state_test.c b/drivers/gpu/drm/tests/drm_atomic_state_test.c
index 2f6ac7a09f44..bc27f65b2823 100644
--- a/drivers/gpu/drm/tests/drm_atomic_state_test.c
+++ b/drivers/gpu/drm/tests/drm_atomic_state_test.c
@@ -156,24 +156,29 @@ static int set_up_atomic_state(struct kunit *test,
if (connector) {
conn_state = drm_atomic_get_connector_state(state, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+ if (IS_ERR(conn_state))
+ return PTR_ERR(conn_state);
ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
- KUNIT_EXPECT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
}
crtc_state = drm_atomic_get_crtc_state(state, crtc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
ret = drm_atomic_set_mode_for_crtc(crtc_state, &drm_atomic_test_mode);
- KUNIT_EXPECT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
crtc_state->enable = true;
crtc_state->active = true;
if (connector) {
ret = drm_atomic_commit(state);
- KUNIT_ASSERT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
} else {
// dummy connector mask
crtc_state->connector_mask = DRM_TEST_CONN_0;
@@ -206,7 +211,13 @@ static void drm_test_check_connector_changed_modeset(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
// first modeset to enable
+retry_set_up:
ret = set_up_atomic_state(test, priv, old_conn, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_set_up;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -277,13 +288,26 @@ static void drm_test_check_valid_clones(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_set_up:
ret = set_up_atomic_state(test, priv, NULL, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_set_up;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+retry:
crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ if (PTR_ERR(crtc_state) == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
crtc_state->encoder_mask = param->encoder_mask;
@@ -292,6 +316,12 @@ static void drm_test_check_valid_clones(struct kunit *test)
crtc_state->mode_changed = true;
ret = drm_atomic_helper_check_modeset(drm, state);
+ if (ret == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_ASSERT_EQ(test, ret, param->expected_result);
drm_modeset_drop_locks(&ctx);
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 8bd412735000..70f9aa702143 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -257,10 +257,16 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -326,10 +332,16 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -397,10 +409,16 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -457,10 +475,17 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
+
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
mode,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -518,10 +543,16 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -580,10 +611,17 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
+
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
mode,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -643,10 +681,16 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -705,10 +749,17 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
+
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
mode,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -870,10 +921,16 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -946,10 +1003,16 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
@@ -1022,10 +1085,16 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1069,10 +1138,16 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1118,10 +1193,16 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1167,10 +1248,16 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1218,10 +1305,16 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
/* You shouldn't be doing that at home. */
@@ -1292,10 +1385,16 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1440,10 +1539,16 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1669,10 +1774,17 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
crtc = priv->crtc;
+
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
mode,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1736,10 +1848,16 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1805,10 +1923,16 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1865,10 +1989,16 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1927,10 +2057,16 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes
drm_modeset_acquire_init(&ctx, 0);
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
@@ -1970,10 +2106,17 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm = &priv->drm;
crtc = priv->crtc;
+
+retry_conn_enable:
ret = drm_kunit_helper_enable_crtc_connector(test, drm,
crtc, conn,
preferred,
&ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c
index 2eda87882e65..6d95447a989d 100644
--- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c
+++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c
@@ -692,7 +692,7 @@ static int threaded_fence_signal(void *arg)
msleep(20);
- return dma_fence_signal(fence);
+ return dma_fence_check_and_signal(fence) ? -EINVAL : 0;
}
static void ttm_bo_validate_move_fence_not_signaled(struct kunit *test)
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index bd27607f8076..acb9197db879 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -268,8 +268,8 @@ static void ttm_bo_release(struct kref *kref)
30 * HZ);
}
- if (bo->bdev->funcs->release_notify)
- bo->bdev->funcs->release_notify(bo);
+ if (bdev->funcs->release_notify)
+ bdev->funcs->release_notify(bo);
drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node);
ttm_mem_io_free(bdev, bo->resource);
@@ -283,7 +283,7 @@ static void ttm_bo_release(struct kref *kref)
ttm_bo_flush_all_fences(bo);
bo->deleted = true;
- spin_lock(&bo->bdev->lru_lock);
+ spin_lock(&bdev->lru_lock);
/*
* Make pinned bos immediately available to
@@ -299,7 +299,7 @@ static void ttm_bo_release(struct kref *kref)
}
kref_init(&bo->kref);
- spin_unlock(&bo->bdev->lru_lock);
+ spin_unlock(&bdev->lru_lock);
INIT_WORK(&bo->delayed_delete, ttm_bo_delayed_delete);
@@ -359,7 +359,6 @@ static int ttm_bo_bounce_temp_buffer(struct ttm_buffer_object *bo,
static int ttm_bo_evict(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx)
{
- struct ttm_device *bdev = bo->bdev;
struct ttm_resource *evict_mem;
struct ttm_placement placement;
struct ttm_place hop;
@@ -370,7 +369,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
dma_resv_assert_held(bo->base.resv);
placement.num_placement = 0;
- bdev->funcs->evict_flags(bo, &placement);
+ bo->bdev->funcs->evict_flags(bo, &placement);
if (!placement.num_placement) {
ret = ttm_bo_wait_ctx(bo, ctx);
@@ -423,16 +422,16 @@ bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
const struct ttm_place *place)
{
struct ttm_resource *res = bo->resource;
- struct ttm_device *bdev = bo->bdev;
dma_resv_assert_held(bo->base.resv);
- if (bo->resource->mem_type == TTM_PL_SYSTEM)
+
+ if (res->mem_type == TTM_PL_SYSTEM)
return true;
/* Don't evict this BO if it's outside of the
* requested placement range
*/
- return ttm_resource_intersects(bdev, res, place, bo->base.size);
+ return ttm_resource_intersects(bo->bdev, res, place, bo->base.size);
}
EXPORT_SYMBOL(ttm_bo_eviction_valuable);
@@ -1027,7 +1026,7 @@ int ttm_bo_init_validate(struct ttm_device *bdev, struct ttm_buffer_object *bo,
struct sg_table *sg, struct dma_resv *resv,
void (*destroy) (struct ttm_buffer_object *))
{
- struct ttm_operation_ctx ctx = { interruptible, false };
+ struct ttm_operation_ctx ctx = { .interruptible = interruptible };
int ret;
ret = ttm_bo_init_reserved(bdev, bo, type, placement, alignment, &ctx,
@@ -1108,10 +1107,13 @@ struct ttm_bo_swapout_walk {
static s64
ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
{
- struct ttm_place place = {.mem_type = bo->resource->mem_type};
+ struct ttm_resource *res = bo->resource;
+ struct ttm_place place = { .mem_type = res->mem_type };
struct ttm_bo_swapout_walk *swapout_walk =
container_of(walk, typeof(*swapout_walk), walk);
struct ttm_operation_ctx *ctx = walk->arg.ctx;
+ struct ttm_device *bdev = bo->bdev;
+ struct ttm_tt *tt = bo->ttm;
s64 ret;
/*
@@ -1120,20 +1122,19 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
* The driver may use the fact that we're moving from SYSTEM
* as an indication that we're about to swap out.
*/
- if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, &place)) {
+ if (bo->pin_count || !bdev->funcs->eviction_valuable(bo, &place)) {
ret = -EBUSY;
goto out;
}
- if (!bo->ttm || !ttm_tt_is_populated(bo->ttm) ||
- bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL ||
- bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED) {
+ if (!tt || !ttm_tt_is_populated(tt) ||
+ tt->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_SWAPPED)) {
ret = -EBUSY;
goto out;
}
if (bo->deleted) {
- pgoff_t num_pages = bo->ttm->num_pages;
+ pgoff_t num_pages = tt->num_pages;
ret = ttm_bo_wait_ctx(bo, ctx);
if (ret)
@@ -1147,7 +1148,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
/*
* Move to system cached
*/
- if (bo->resource->mem_type != TTM_PL_SYSTEM) {
+ if (res->mem_type != TTM_PL_SYSTEM) {
struct ttm_resource *evict_mem;
struct ttm_place hop;
@@ -1174,21 +1175,21 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
goto out;
ttm_bo_unmap_virtual(bo);
- if (bo->bdev->funcs->swap_notify)
- bo->bdev->funcs->swap_notify(bo);
+ if (bdev->funcs->swap_notify)
+ bdev->funcs->swap_notify(bo);
- if (ttm_tt_is_populated(bo->ttm)) {
- spin_lock(&bo->bdev->lru_lock);
- ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bo->bdev->lru_lock);
+ if (ttm_tt_is_populated(tt)) {
+ spin_lock(&bdev->lru_lock);
+ ttm_resource_del_bulk_move(res, bo);
+ spin_unlock(&bdev->lru_lock);
- ret = ttm_tt_swapout(bo->bdev, bo->ttm, swapout_walk->gfp_flags);
+ ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
- spin_lock(&bo->bdev->lru_lock);
+ spin_lock(&bdev->lru_lock);
if (ret)
- ttm_resource_add_bulk_move(bo->resource, bo);
- ttm_resource_move_to_lru_tail(bo->resource);
- spin_unlock(&bo->bdev->lru_lock);
+ ttm_resource_add_bulk_move(res, bo);
+ ttm_resource_move_to_lru_tail(res);
+ spin_unlock(&bdev->lru_lock);
}
out:
@@ -1261,6 +1262,7 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo)
int ttm_bo_populate(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx)
{
+ struct ttm_device *bdev = bo->bdev;
struct ttm_tt *tt = bo->ttm;
bool swapped;
int ret;
@@ -1271,16 +1273,16 @@ int ttm_bo_populate(struct ttm_buffer_object *bo,
return 0;
swapped = ttm_tt_is_swapped(tt);
- ret = ttm_tt_populate(bo->bdev, tt, ctx);
+ ret = ttm_tt_populate(bdev, tt, ctx);
if (ret)
return ret;
if (swapped && !ttm_tt_is_swapped(tt) && !bo->pin_count &&
bo->resource) {
- spin_lock(&bo->bdev->lru_lock);
+ spin_lock(&bdev->lru_lock);
ttm_resource_add_bulk_move(bo->resource, bo);
ttm_resource_move_to_lru_tail(bo->resource);
- spin_unlock(&bo->bdev->lru_lock);
+ spin_unlock(&bdev->lru_lock);
}
return 0;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 2ff35d55e462..cabcfeaa70dc 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -174,13 +174,13 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
dst_iter = ttm_kmap_iter_linear_io_init(&_dst_iter.io, bdev, dst_mem);
if (PTR_ERR(dst_iter) == -EINVAL && dst_man->use_tt)
- dst_iter = ttm_kmap_iter_tt_init(&_dst_iter.tt, bo->ttm);
+ dst_iter = ttm_kmap_iter_tt_init(&_dst_iter.tt, ttm);
if (IS_ERR(dst_iter))
return PTR_ERR(dst_iter);
src_iter = ttm_kmap_iter_linear_io_init(&_src_iter.io, bdev, src_mem);
if (PTR_ERR(src_iter) == -EINVAL && src_man->use_tt)
- src_iter = ttm_kmap_iter_tt_init(&_src_iter.tt, bo->ttm);
+ src_iter = ttm_kmap_iter_tt_init(&_src_iter.tt, ttm);
if (IS_ERR(src_iter)) {
ret = PTR_ERR(src_iter);
goto out_src_iter;
@@ -318,11 +318,11 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo,
{
struct ttm_resource *mem = bo->resource;
- if (bo->resource->bus.addr) {
+ if (mem->bus.addr) {
map->bo_kmap_type = ttm_bo_map_premapped;
- map->virtual = ((u8 *)bo->resource->bus.addr) + offset;
+ map->virtual = ((u8 *)mem->bus.addr) + offset;
} else {
- resource_size_t res = bo->resource->bus.offset + offset;
+ resource_size_t res = mem->bus.offset + offset;
map->bo_kmap_type = ttm_bo_map_iomap;
if (mem->bus.caching == ttm_write_combined)
@@ -343,13 +343,10 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
struct ttm_bo_kmap_obj *map)
{
struct ttm_resource *mem = bo->resource;
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
+ struct ttm_operation_ctx ctx = { };
struct ttm_tt *ttm = bo->ttm;
struct ttm_resource_manager *man =
- ttm_manager_type(bo->bdev, bo->resource->mem_type);
+ ttm_manager_type(bo->bdev, mem->mem_type);
pgprot_t prot;
int ret;
@@ -428,20 +425,21 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
unsigned long start_page, unsigned long num_pages,
struct ttm_bo_kmap_obj *map)
{
+ struct ttm_resource *res = bo->resource;
unsigned long offset, size;
int ret;
map->virtual = NULL;
map->bo = bo;
- if (num_pages > PFN_UP(bo->resource->size))
+ if (num_pages > PFN_UP(res->size))
return -EINVAL;
- if ((start_page + num_pages) > PFN_UP(bo->resource->size))
+ if ((start_page + num_pages) > PFN_UP(res->size))
return -EINVAL;
- ret = ttm_mem_io_reserve(bo->bdev, bo->resource);
+ ret = ttm_mem_io_reserve(bo->bdev, res);
if (ret)
return ret;
- if (!bo->resource->bus.is_iomem) {
+ if (!res->bus.is_iomem) {
return ttm_bo_kmap_ttm(bo, start_page, num_pages, map);
} else {
offset = start_page << PAGE_SHIFT;
@@ -530,10 +528,7 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
iosys_map_set_vaddr_iomem(map, vaddr_iomem);
} else {
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
+ struct ttm_operation_ctx ctx = { };
struct ttm_tt *ttm = bo->ttm;
pgprot_t prot;
void *vaddr;
@@ -581,7 +576,7 @@ void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map)
iounmap(map->vaddr_iomem);
iosys_map_clear(map);
- ttm_mem_io_free(bo->bdev, bo->resource);
+ ttm_mem_io_free(bo->bdev, mem);
}
EXPORT_SYMBOL(ttm_bo_vunmap);
@@ -644,12 +639,11 @@ static int ttm_bo_move_to_ghost(struct ttm_buffer_object *bo,
static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo,
struct dma_fence *fence)
{
- struct ttm_device *bdev = bo->bdev;
struct ttm_resource_manager *from;
struct dma_fence *tmp;
int i;
- from = ttm_manager_type(bdev, bo->resource->mem_type);
+ from = ttm_manager_type(bo->bdev, bo->resource->mem_type);
/**
* BO doesn't have a TTM we need to bind/unbind. Just remember
@@ -743,8 +737,8 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
void ttm_bo_move_sync_cleanup(struct ttm_buffer_object *bo,
struct ttm_resource *new_mem)
{
- struct ttm_device *bdev = bo->bdev;
- struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bo->bdev, new_mem->mem_type);
int ret;
ret = ttm_bo_wait_free_node(bo, man->use_tt);
@@ -848,13 +842,12 @@ static int ttm_lru_walk_ticketlock(struct ttm_bo_lru_cursor *curs,
struct ttm_buffer_object *bo)
{
struct ttm_lru_walk_arg *arg = curs->arg;
- struct dma_resv *resv = bo->base.resv;
int ret;
if (arg->ctx->interruptible)
- ret = dma_resv_lock_interruptible(resv, arg->ticket);
+ ret = dma_resv_lock_interruptible(bo->base.resv, arg->ticket);
else
- ret = dma_resv_lock(resv, arg->ticket);
+ ret = dma_resv_lock(bo->base.resv, arg->ticket);
if (!ret) {
curs->needs_unlock = true;
@@ -1098,7 +1091,7 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
.num_placement = 1,
.placement = &sys_placement_flags,
};
- struct ttm_tt *tt = bo->ttm;
+ struct ttm_device *bdev = bo->bdev;
long lret;
dma_resv_assert_held(bo->base.resv);
@@ -1120,19 +1113,19 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
return lret;
if (bo->bulk_move) {
- spin_lock(&bo->bdev->lru_lock);
+ spin_lock(&bdev->lru_lock);
ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bo->bdev->lru_lock);
+ spin_unlock(&bdev->lru_lock);
}
- lret = ttm_tt_backup(bo->bdev, tt, (struct ttm_backup_flags)
+ lret = ttm_tt_backup(bdev, bo->ttm, (struct ttm_backup_flags)
{.purge = flags.purge,
.writeback = flags.writeback});
if (lret <= 0 && bo->bulk_move) {
- spin_lock(&bo->bdev->lru_lock);
+ spin_lock(&bdev->lru_lock);
ttm_resource_add_bulk_move(bo->resource, bo);
- spin_unlock(&bo->bdev->lru_lock);
+ spin_unlock(&bdev->lru_lock);
}
if (lret < 0 && lret != -EINTR)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index e6abc7b40b18..a80510489c45 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -186,7 +186,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
{
struct vm_area_struct *vma = vmf->vma;
struct ttm_buffer_object *bo = vma->vm_private_data;
- struct ttm_device *bdev = bo->bdev;
unsigned long page_offset;
unsigned long page_last;
unsigned long pfn;
@@ -205,7 +204,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
if (unlikely(ret != 0))
return ret;
- err = ttm_mem_io_reserve(bdev, bo->resource);
+ err = ttm_mem_io_reserve(bo->bdev, bo->resource);
if (unlikely(err != 0))
return VM_FAULT_SIGBUS;
@@ -293,7 +292,6 @@ vm_fault_t ttm_bo_vm_dummy_page(struct vm_fault *vmf, pgprot_t prot)
{
struct vm_area_struct *vma = vmf->vma;
struct ttm_buffer_object *bo = vma->vm_private_data;
- struct drm_device *ddev = bo->base.dev;
vm_fault_t ret = VM_FAULT_NOPAGE;
unsigned long address;
unsigned long pfn;
@@ -305,7 +303,8 @@ vm_fault_t ttm_bo_vm_dummy_page(struct vm_fault *vmf, pgprot_t prot)
return VM_FAULT_OOM;
/* Set the page to be freed using drmm release action */
- if (drmm_add_action_or_reset(ddev, ttm_bo_release_dummy_page, page))
+ if (drmm_add_action_or_reset(bo->base.dev, ttm_bo_release_dummy_page,
+ page))
return VM_FAULT_OOM;
pfn = page_to_pfn(page);
@@ -322,10 +321,9 @@ EXPORT_SYMBOL(ttm_bo_vm_dummy_page);
vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
- pgprot_t prot;
struct ttm_buffer_object *bo = vma->vm_private_data;
- struct drm_device *ddev = bo->base.dev;
vm_fault_t ret;
+ pgprot_t prot;
int idx;
ret = ttm_bo_vm_reserve(bo, vmf);
@@ -333,7 +331,7 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
return ret;
prot = vma->vm_page_prot;
- if (drm_dev_enter(ddev, &idx)) {
+ if (drm_dev_enter(bo->base.dev, &idx)) {
ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
drm_dev_exit(idx);
} else {
diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c
index 9a51afaf0749..d3bfb9a696a7 100644
--- a/drivers/gpu/drm/ttm/ttm_device.c
+++ b/drivers/gpu/drm/ttm/ttm_device.c
@@ -135,10 +135,7 @@ out:
*/
int ttm_device_prepare_hibernation(struct ttm_device *bdev)
{
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false,
- };
+ struct ttm_operation_ctx ctx = { };
int ret;
do {
diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index 18b6db015619..217e45958099 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -845,32 +845,34 @@ EXPORT_SYMBOL(ttm_pool_alloc);
int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt,
const struct ttm_operation_ctx *ctx)
{
+ struct ttm_pool_tt_restore *restore = tt->restore;
struct ttm_pool_alloc_state alloc;
if (WARN_ON(!ttm_tt_is_backed_up(tt)))
return -EINVAL;
- if (!tt->restore) {
+ if (!restore) {
gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
ttm_pool_alloc_state_init(tt, &alloc);
if (ctx->gfp_retry_mayfail)
gfp |= __GFP_RETRY_MAYFAIL;
- tt->restore = kzalloc(sizeof(*tt->restore), gfp);
- if (!tt->restore)
+ restore = kzalloc(sizeof(*restore), gfp);
+ if (!restore)
return -ENOMEM;
- tt->restore->snapshot_alloc = alloc;
- tt->restore->pool = pool;
- tt->restore->restored_pages = 1;
- } else {
- struct ttm_pool_tt_restore *restore = tt->restore;
- int ret;
+ restore->snapshot_alloc = alloc;
+ restore->pool = pool;
+ restore->restored_pages = 1;
+ tt->restore = restore;
+ } else {
alloc = restore->snapshot_alloc;
- if (ttm_pool_restore_valid(tt->restore)) {
- ret = ttm_pool_restore_commit(restore, tt->backup, ctx, &alloc);
+ if (ttm_pool_restore_valid(restore)) {
+ int ret = ttm_pool_restore_commit(restore, tt->backup,
+ ctx, &alloc);
+
if (ret)
return ret;
}
@@ -878,7 +880,7 @@ int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt,
return 0;
}
- return __ttm_pool_alloc(pool, tt, ctx, &alloc, tt->restore);
+ return __ttm_pool_alloc(pool, tt, ctx, &alloc, restore);
}
/**
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index f5aa29dc6ec0..192fca24f37e 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -446,9 +446,6 @@ bool ttm_resource_intersects(struct ttm_device *bdev,
{
struct ttm_resource_manager *man;
- if (!res)
- return false;
-
man = ttm_manager_type(bdev, res->mem_type);
if (!place || !man->func->intersects)
return true;
@@ -548,10 +545,7 @@ EXPORT_SYMBOL(ttm_resource_manager_init);
int ttm_resource_manager_evict_all(struct ttm_device *bdev,
struct ttm_resource_manager *man)
{
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false,
- };
+ struct ttm_operation_ctx ctx = { };
struct dma_fence *fence;
int ret, i;
@@ -628,11 +622,11 @@ ttm_resource_cursor_check_bulk(struct ttm_resource_cursor *cursor,
struct ttm_lru_item *next_lru)
{
struct ttm_resource *next = ttm_lru_item_to_res(next_lru);
- struct ttm_lru_bulk_move *bulk = NULL;
- struct ttm_buffer_object *bo = next->bo;
+ struct ttm_lru_bulk_move *bulk;
lockdep_assert_held(&cursor->man->bdev->lru_lock);
- bulk = bo->bulk_move;
+
+ bulk = next->bo->bulk_move;
if (cursor->bulk != bulk) {
if (bulk) {
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 611d20ab966d..af33fa020249 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -456,7 +456,7 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_unpopulate);
/* Test the shrinker functions and dump the result */
static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data)
{
- struct ttm_operation_ctx ctx = { false, false };
+ struct ttm_operation_ctx ctx = { };
seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL));
return 0;
diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile
index fcf710926057..b7d673f1153b 100644
--- a/drivers/gpu/drm/v3d/Makefile
+++ b/drivers/gpu/drm/v3d/Makefile
@@ -13,8 +13,7 @@ v3d-y := \
v3d_trace_points.o \
v3d_sched.o \
v3d_sysfs.o \
- v3d_submit.o \
- v3d_gemfs.o
+ v3d_submit.o
v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index d9547f5117b9..c4316b768b3d 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -114,7 +114,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
if (IS_ERR(sgt))
return PTR_ERR(sgt);
- if (!v3d->gemfs)
+ if (!drm_gem_get_huge_mnt(obj->dev))
align = SZ_4K;
else if (obj->size >= SZ_1M)
align = SZ_1M;
@@ -150,12 +150,10 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
size_t unaligned_size)
{
struct drm_gem_shmem_object *shmem_obj;
- struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_bo *bo;
int ret;
- shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
- v3d->gemfs);
+ shmem_obj = drm_gem_shmem_create(dev, unaligned_size);
if (IS_ERR(shmem_obj))
return ERR_CAST(shmem_obj);
bo = to_v3d_bo(&shmem_obj->base);
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index e8a46c8bad8a..8faa9382846f 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -107,7 +107,7 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
args->value = v3d->perfmon_info.max_counters;
return 0;
case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES:
- args->value = !!v3d->gemfs;
+ args->value = !!drm_gem_get_huge_mnt(dev);
return 0;
case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER:
mutex_lock(&v3d->reset_lock);
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index 1884686985b8..99a39329bb85 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -158,11 +158,6 @@ struct v3d_dev {
struct drm_mm mm;
spinlock_t mm_lock;
- /*
- * tmpfs instance used for shmem backed objects
- */
- struct vfsmount *gemfs;
-
struct work_struct overflow_mem_work;
struct v3d_queue_state queue[V3D_MAX_QUEUES];
@@ -569,6 +564,7 @@ extern const struct dma_fence_ops v3d_fence_ops;
struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
/* v3d_gem.c */
+extern bool super_pages;
int v3d_gem_init(struct drm_device *dev);
void v3d_gem_destroy(struct drm_device *dev);
void v3d_reset_sms(struct v3d_dev *v3d);
@@ -576,11 +572,6 @@ void v3d_reset(struct v3d_dev *v3d);
void v3d_invalidate_caches(struct v3d_dev *v3d);
void v3d_clean_caches(struct v3d_dev *v3d);
-/* v3d_gemfs.c */
-extern bool super_pages;
-void v3d_gemfs_init(struct v3d_dev *v3d);
-void v3d_gemfs_fini(struct v3d_dev *v3d);
-
/* v3d_submit.c */
void v3d_job_cleanup(struct v3d_job *job);
void v3d_job_put(struct v3d_job *job);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 5a180dc6c452..697b0b3ca92c 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -259,6 +259,24 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
v3d_invalidate_slices(v3d, 0);
}
+static void
+v3d_huge_mnt_init(struct v3d_dev *v3d)
+{
+ int err = 0;
+
+ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
+ err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
+
+ if (drm_gem_get_huge_mnt(&v3d->drm))
+ drm_info(&v3d->drm, "Using Transparent Hugepages\n");
+ else if (err)
+ drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n",
+ err);
+ else
+ drm_notice(&v3d->drm,
+ "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
+}
+
int
v3d_gem_init(struct drm_device *dev)
{
@@ -310,7 +328,7 @@ v3d_gem_init(struct drm_device *dev)
v3d_init_hw_state(v3d);
v3d_mmu_set_page_table(v3d);
- v3d_gemfs_init(v3d);
+ v3d_huge_mnt_init(v3d);
ret = v3d_sched_init(v3d);
if (ret) {
@@ -330,7 +348,6 @@ v3d_gem_destroy(struct drm_device *dev)
enum v3d_queue q;
v3d_sched_fini(v3d);
- v3d_gemfs_fini(v3d);
/* Waiting for jobs to finish would need to be done before
* unregistering V3D.
diff --git a/drivers/gpu/drm/v3d/v3d_gemfs.c b/drivers/gpu/drm/v3d/v3d_gemfs.c
deleted file mode 100644
index bf351fc0d488..000000000000
--- a/drivers/gpu/drm/v3d/v3d_gemfs.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* Copyright (C) 2024 Raspberry Pi */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/fs_context.h>
-
-#include <drm/drm_print.h>
-
-#include "v3d_drv.h"
-
-void v3d_gemfs_init(struct v3d_dev *v3d)
-{
- struct file_system_type *type;
- struct fs_context *fc;
- struct vfsmount *gemfs;
- int ret;
-
- /*
- * By creating our own shmemfs mountpoint, we can pass in
- * mount flags that better match our usecase. However, we
- * only do so on platforms which benefit from it.
- */
- if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
- goto err;
-
- /* The user doesn't want to enable Super Pages */
- if (!super_pages)
- goto err;
-
- type = get_fs_type("tmpfs");
- if (!type)
- goto err;
-
- fc = fs_context_for_mount(type, SB_KERNMOUNT);
- if (IS_ERR(fc))
- goto err;
- ret = vfs_parse_fs_string(fc, "source", "tmpfs");
- if (!ret)
- ret = vfs_parse_fs_string(fc, "huge", "within_size");
- if (!ret)
- gemfs = fc_mount_longterm(fc);
- put_fs_context(fc);
- if (ret)
- goto err;
-
- v3d->gemfs = gemfs;
- drm_info(&v3d->drm, "Using Transparent Hugepages\n");
-
- return;
-
-err:
- v3d->gemfs = NULL;
- drm_notice(&v3d->drm,
- "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
-}
-
-void v3d_gemfs_fini(struct v3d_dev *v3d)
-{
- if (v3d->gemfs)
- kern_unmount(v3d->gemfs);
-}
diff --git a/drivers/gpu/drm/vgem/Kconfig b/drivers/gpu/drm/vgem/Kconfig
new file mode 100644
index 000000000000..c419cdadd54c
--- /dev/null
+++ b/drivers/gpu/drm/vgem/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_VGEM
+ tristate "Virtual GEM provider"
+ depends on DRM && MMU
+ select DRM_GEM_SHMEM_HELPER
+ help
+ Choose this option to get a virtual graphics memory manager,
+ as used by Mesa's software renderer for enhanced performance.
+ If M is selected the module will be called vgem.
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index a6749dd6a725..8dcc85cb8d42 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -199,16 +199,10 @@ endif
# i915 Display compat #defines and #includes
subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \
- -I$(src)/display/ext \
-I$(src)/compat-i915-headers \
-I$(srctree)/drivers/gpu/drm/i915/display/ \
-Ddrm_i915_private=xe_device
-# Rule to build SOC code shared with i915
-$(obj)/i915-soc/%.o: $(srctree)/drivers/gpu/drm/i915/soc/%.c FORCE
- $(call cmd,force_checksrc)
- $(call if_changed_rule,cc_o_c)
-
# Rule to build display code shared with i915
$(obj)/i915-display/%.o: $(srctree)/drivers/gpu/drm/i915/display/%.c FORCE
$(call cmd,force_checksrc)
@@ -216,12 +210,10 @@ $(obj)/i915-display/%.o: $(srctree)/drivers/gpu/drm/i915/display/%.c FORCE
# Display code specific to xe
xe-$(CONFIG_DRM_XE_DISPLAY) += \
- display/ext/i915_irq.o \
display/intel_bo.o \
display/intel_fb_bo.o \
display/intel_fbdev_fb.o \
display/xe_display.o \
- display/xe_display_misc.o \
display/xe_display_rpm.o \
display/xe_display_wa.o \
display/xe_dsb_buffer.o \
@@ -232,11 +224,6 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
display/xe_stolen.o \
display/xe_tdf.o
-# SOC code shared with i915
-xe-$(CONFIG_DRM_XE_DISPLAY) += \
- i915-soc/intel_dram.o \
- i915-soc/intel_rom.o
-
# Display code shared with i915
xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/icl_dsi.o \
@@ -271,6 +258,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_display_power_map.o \
i915-display/intel_display_power_well.o \
i915-display/intel_display_rpm.o \
+ i915-display/intel_display_rps.o \
i915-display/intel_display_trace.o \
i915-display/intel_display_utils.o \
i915-display/intel_display_wa.o \
@@ -287,6 +275,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_dpll.o \
i915-display/intel_dpll_mgr.o \
i915-display/intel_dpt_common.o \
+ i915-display/intel_dram.o \
i915-display/intel_drrs.o \
i915-display/intel_dsb.o \
i915-display/intel_dsi.o \
@@ -314,14 +303,16 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_modeset_setup.o \
i915-display/intel_modeset_verify.o \
i915-display/intel_panel.o \
+ i915-display/intel_parent.o \
+ i915-display/intel_pch.o \
i915-display/intel_pfit.o \
i915-display/intel_plane.o \
i915-display/intel_pmdemand.o \
- i915-display/intel_pch.o \
i915-display/intel_pps.o \
i915-display/intel_psr.o \
i915-display/intel_qp_tables.o \
i915-display/intel_quirks.o \
+ i915-display/intel_rom.o \
i915-display/intel_snps_hdmi_pll.o \
i915-display/intel_snps_phy.o \
i915-display/intel_tc.o \
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h
deleted file mode 100644
index 0548b2e0316f..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/* Copyright © 2025 Intel Corporation */
-
-#ifndef __I915_GEM_OBJECT_H__
-#define __I915_GEM_OBJECT_H__
-
-struct dma_fence;
-
-static inline void i915_gem_fence_wait_priority_display(struct dma_fence *fence)
-{
-}
-
-#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h
deleted file mode 100644
index 48e3256ba37e..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2024 Intel Corporation
- */
-
-#ifndef _I915_GEM_STOLEN_H_
-#define _I915_GEM_STOLEN_H_
-
-#include <linux/types.h>
-
-struct drm_device;
-struct intel_stolen_node;
-
-int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
- unsigned int align, u64 start, u64 end);
-
-int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size,
- unsigned int align);
-
-void i915_gem_stolen_remove_node(struct intel_stolen_node *node);
-
-bool i915_gem_stolen_initialized(struct drm_device *drm);
-
-bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node);
-
-u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node);
-
-u64 i915_gem_stolen_area_address(struct drm_device *drm);
-
-u64 i915_gem_stolen_area_size(struct drm_device *drm);
-
-u64 i915_gem_stolen_node_address(struct intel_stolen_node *node);
-
-u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node);
-
-struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm);
-
-void i915_gem_stolen_node_free(const struct intel_stolen_node *node);
-
-#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gt/intel_gt_types.h b/drivers/gpu/drm/xe/compat-i915-headers/gt/intel_gt_types.h
deleted file mode 100644
index c15806d6c4f7..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/gt/intel_gt_types.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#ifndef __INTEL_GT_TYPES__
-#define __INTEL_GT_TYPES__
-
-#define intel_gt_support_legacy_fencing(gt) 0
-
-#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_active.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_active.h
deleted file mode 100644
index 6f0ab3753563..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_active.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2022 Intel Corporation
- */
-
-#ifndef _I915_ACTIVE_H_
-#define _I915_ACTIVE_H_
-
-#include "i915_active_types.h"
-
-static inline void i915_active_init(struct i915_active *ref,
- int (*active)(struct i915_active *ref),
- void (*retire)(struct i915_active *ref),
- unsigned long flags)
-{
- (void) active;
- (void) retire;
-}
-
-#define i915_active_fini(active) do { } while (0)
-
-#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_active_types.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_active_types.h
deleted file mode 100644
index 8c31f9a8b168..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_active_types.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef _I915_ACTIVE_TYPES_H_
-#define _I915_ACTIVE_TYPES_H_
-
-struct i915_active {};
-#define I915_ACTIVE_RETIRE_SLEEPS 0
-
-#endif /* _I915_ACTIVE_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h
index 3e79a74ff7de..04d1925f9a19 100644
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h
+++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h
@@ -19,19 +19,4 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
return container_of(dev, struct drm_i915_private, drm);
}
-/* compat platform checks only for soc/ usage */
-#define IS_PLATFORM(xe, x) ((xe)->info.platform == x)
-#define IS_I915G(dev_priv) (dev_priv && 0)
-#define IS_I915GM(dev_priv) (dev_priv && 0)
-#define IS_PINEVIEW(dev_priv) (dev_priv && 0)
-#define IS_VALLEYVIEW(dev_priv) (dev_priv && 0)
-#define IS_CHERRYVIEW(dev_priv) (dev_priv && 0)
-#define IS_HASWELL(dev_priv) (dev_priv && 0)
-#define IS_BROADWELL(dev_priv) (dev_priv && 0)
-#define IS_BROXTON(dev_priv) (dev_priv && 0)
-#define IS_GEMINILAKE(dev_priv) (dev_priv && 0)
-#define IS_DG2(dev_priv) IS_PLATFORM(dev_priv, XE_DG2)
-
-#define IS_MOBILE(xe) (xe && 0)
-
#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_irq.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_irq.h
deleted file mode 100644
index 61707a07f91f..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_irq.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include "../../i915/i915_irq.h"
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h
index bcd441dc0fce..3639721f0bf8 100644
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h
+++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h
@@ -3,11 +3,5 @@
* Copyright © 2023 Intel Corporation
*/
-/* for soc/ */
-#ifndef MISSING_CASE
-#define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \
- __stringify(x), (long)(x))
-#endif
-
/* for a couple of users under i915/display */
#define i915_inject_probe_failure(unused) ((unused) && 0)
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_vgpu.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_vgpu.h
deleted file mode 100644
index 4931c7198f13..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/i915_vgpu.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#ifndef _I915_VGPU_H_
-#define _I915_VGPU_H_
-
-#include <linux/types.h>
-
-struct drm_i915_private;
-
-static inline bool intel_vgpu_active(struct drm_i915_private *i915)
-{
- return false;
-}
-
-#endif /* _I915_VGPU_H_ */
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h
deleted file mode 100644
index 2a32faea9db5..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/intel_wakeref.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include <linux/types.h>
-
-typedef struct ref_tracker *intel_wakeref_t;
-
-#define INTEL_WAKEREF_DEF ERR_PTR(-ENOENT)
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h b/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h
deleted file mode 100644
index 97fd0ddf0b3a..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#ifndef __INTEL_PXP_H__
-#define __INTEL_PXP_H__
-
-#include <linux/errno.h>
-#include <linux/types.h>
-
-#include "xe_pxp.h"
-
-struct drm_gem_object;
-
-static inline int intel_pxp_key_check(struct drm_gem_object *obj, bool assign)
-{
- /*
- * The assign variable is used in i915 to assign the key to the BO at
- * first submission time. In Xe the key is instead assigned at BO
- * creation time, so the assign variable must always be false.
- */
- if (assign)
- return -EINVAL;
-
- return xe_pxp_obj_key_check(obj);
-}
-
-#endif
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_dram.h b/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_dram.h
deleted file mode 100644
index 65707e20c557..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_dram.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include "../../../i915/soc/intel_dram.h"
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_gmch.h b/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_gmch.h
deleted file mode 100644
index 33c5257b3a71..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_gmch.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include "../../../i915/soc/intel_gmch.h"
diff --git a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_rom.h b/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_rom.h
deleted file mode 100644
index 05cbfb697b2b..000000000000
--- a/drivers/gpu/drm/xe/compat-i915-headers/soc/intel_rom.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2024 Intel Corporation
- */
-
-#include "../../../i915/soc/intel_rom.h"
diff --git a/drivers/gpu/drm/xe/display/ext/i915_irq.c b/drivers/gpu/drm/xe/display/ext/i915_irq.c
deleted file mode 100644
index 3c6bca66ddab..000000000000
--- a/drivers/gpu/drm/xe/display/ext/i915_irq.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include "i915_irq.h"
-#include "i915_reg.h"
-#include "intel_uncore.h"
-
-void gen2_irq_reset(struct intel_uncore *uncore, struct i915_irq_regs regs)
-{
- intel_uncore_write(uncore, regs.imr, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.imr);
-
- intel_uncore_write(uncore, regs.ier, 0);
-
- /* IIR can theoretically queue up two events. Be paranoid. */
- intel_uncore_write(uncore, regs.iir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.iir);
- intel_uncore_write(uncore, regs.iir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.iir);
-}
-
-/*
- * We should clear IMR at preinstall/uninstall, and just check at postinstall.
- */
-void gen2_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg)
-{
- struct xe_device *xe = container_of(uncore, struct xe_device, uncore);
- u32 val = intel_uncore_read(uncore, reg);
-
- if (val == 0)
- return;
-
- drm_WARN(&xe->drm, 1,
- "Interrupt register 0x%x is not zero: 0x%08x\n",
- i915_mmio_reg_offset(reg), val);
- intel_uncore_write(uncore, reg, 0xffffffff);
- intel_uncore_posting_read(uncore, reg);
- intel_uncore_write(uncore, reg, 0xffffffff);
- intel_uncore_posting_read(uncore, reg);
-}
-
-void gen2_irq_init(struct intel_uncore *uncore, struct i915_irq_regs regs,
- u32 imr_val, u32 ier_val)
-{
- gen2_assert_iir_is_zero(uncore, regs.iir);
-
- intel_uncore_write(uncore, regs.ier, ier_val);
- intel_uncore_write(uncore, regs.imr, imr_val);
- intel_uncore_posting_read(uncore, regs.imr);
-}
-
-void gen2_error_reset(struct intel_uncore *uncore, struct i915_error_regs regs)
-{
- intel_uncore_write(uncore, regs.emr, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.emr);
-
- intel_uncore_write(uncore, regs.eir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.eir);
- intel_uncore_write(uncore, regs.eir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.eir);
-}
-
-void gen2_error_init(struct intel_uncore *uncore, struct i915_error_regs regs,
- u32 emr_val)
-{
- intel_uncore_write(uncore, regs.eir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.eir);
- intel_uncore_write(uncore, regs.eir, 0xffffffff);
- intel_uncore_posting_read(uncore, regs.eir);
-
- intel_uncore_write(uncore, regs.emr, emr_val);
- intel_uncore_posting_read(uncore, regs.emr);
-}
-
-bool intel_irqs_enabled(struct xe_device *xe)
-{
- return atomic_read(&xe->irq.enabled);
-}
-
-void intel_synchronize_irq(struct xe_device *xe)
-{
- synchronize_irq(to_pci_dev(xe->drm.dev)->irq);
-}
diff --git a/drivers/gpu/drm/xe/display/intel_bo.c b/drivers/gpu/drm/xe/display/intel_bo.c
index bad2243b9114..e8049a255d21 100644
--- a/drivers/gpu/drm/xe/display/intel_bo.c
+++ b/drivers/gpu/drm/xe/display/intel_bo.c
@@ -3,9 +3,10 @@
#include <drm/drm_gem.h>
-#include "xe_bo.h"
#include "intel_bo.h"
#include "intel_frontbuffer.h"
+#include "xe_bo.h"
+#include "xe_pxp.h"
bool intel_bo_is_tiled(struct drm_gem_object *obj)
{
@@ -29,6 +30,11 @@ bool intel_bo_is_protected(struct drm_gem_object *obj)
return xe_bo_is_protected(gem_to_xe_bo(obj));
}
+int intel_bo_key_check(struct drm_gem_object *obj)
+{
+ return xe_pxp_obj_key_check(obj);
+}
+
int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
return drm_gem_prime_mmap(obj, vma);
diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
index 8b0afa270216..eda65a05f601 100644
--- a/drivers/gpu/drm/xe/display/xe_display.c
+++ b/drivers/gpu/drm/xe/display/xe_display.c
@@ -17,7 +17,6 @@
#include <drm/intel/display_parent_interface.h>
#include <uapi/drm/xe_drm.h>
-#include "soc/intel_dram.h"
#include "intel_acpi.h"
#include "intel_audio.h"
#include "intel_bw.h"
@@ -29,6 +28,7 @@
#include "intel_dmc.h"
#include "intel_dmc_wl.h"
#include "intel_dp.h"
+#include "intel_dram.h"
#include "intel_encoder.h"
#include "intel_fbdev.h"
#include "intel_hdcp.h"
@@ -36,7 +36,10 @@
#include "intel_opregion.h"
#include "skl_watermark.h"
#include "xe_display_rpm.h"
+#include "xe_hdcp_gsc.h"
#include "xe_module.h"
+#include "xe_panic.h"
+#include "xe_stolen.h"
/* Ensure drm and display members are placed properly. */
INTEL_DISPLAY_MEMBER_STATIC_ASSERT(struct xe_device, drm, display);
@@ -122,7 +125,7 @@ int xe_display_init_early(struct xe_device *xe)
* Fill the dram structure to get the system dram info. This will be
* used for memory latency calculation.
*/
- err = intel_dram_detect(xe);
+ err = intel_dram_detect(display);
if (err)
goto err_opregion;
@@ -516,8 +519,29 @@ static void display_device_remove(struct drm_device *dev, void *arg)
intel_display_device_remove(display);
}
+static bool irq_enabled(struct drm_device *drm)
+{
+ struct xe_device *xe = to_xe_device(drm);
+
+ return atomic_read(&xe->irq.enabled);
+}
+
+static void irq_synchronize(struct drm_device *drm)
+{
+ synchronize_irq(to_pci_dev(drm->dev)->irq);
+}
+
+static const struct intel_display_irq_interface xe_display_irq_interface = {
+ .enabled = irq_enabled,
+ .synchronize = irq_synchronize,
+};
+
static const struct intel_display_parent_interface parent = {
+ .hdcp = &xe_display_hdcp_interface,
+ .irq = &xe_display_irq_interface,
+ .panic = &xe_display_panic_interface,
.rpm = &xe_display_rpm_interface,
+ .stolen = &xe_display_stolen_interface,
};
/**
diff --git a/drivers/gpu/drm/xe/display/xe_display_misc.c b/drivers/gpu/drm/xe/display/xe_display_misc.c
deleted file mode 100644
index 242c2ef4ca93..000000000000
--- a/drivers/gpu/drm/xe/display/xe_display_misc.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2023 Intel Corporation
- */
-
-#include "intel_display_types.h"
-
-struct pci_dev;
-
-unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode);
-
-unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
-{
- /* ToDo: Implement the actual handling of vga decode */
- return 0;
-}
diff --git a/drivers/gpu/drm/xe/display/xe_display_rpm.c b/drivers/gpu/drm/xe/display/xe_display_rpm.c
index 340f65884812..b3db40035499 100644
--- a/drivers/gpu/drm/xe/display/xe_display_rpm.c
+++ b/drivers/gpu/drm/xe/display/xe_display_rpm.c
@@ -9,6 +9,9 @@
#include "xe_device_types.h"
#include "xe_pm.h"
+/* -ENOENT means we got the ref, but there's no tracking */
+#define INTEL_WAKEREF_DEF ERR_PTR(-ENOENT)
+
static struct ref_tracker *xe_display_rpm_get(const struct drm_device *drm)
{
return xe_pm_runtime_resume_and_get(to_xe_device(drm)) ? INTEL_WAKEREF_DEF : NULL;
diff --git a/drivers/gpu/drm/xe/display/xe_dsb_buffer.c b/drivers/gpu/drm/xe/display/xe_dsb_buffer.c
index 58581d7aaae6..fa0acb11eaad 100644
--- a/drivers/gpu/drm/xe/display/xe_dsb_buffer.c
+++ b/drivers/gpu/drm/xe/display/xe_dsb_buffer.c
@@ -3,44 +3,49 @@
* Copyright 2023, Intel Corporation.
*/
-#include "i915_vma.h"
-#include "intel_display_types.h"
#include "intel_dsb_buffer.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_device_types.h"
+struct intel_dsb_buffer {
+ u32 *cmd_buf;
+ struct xe_bo *bo;
+ size_t buf_size;
+};
+
u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf)
{
- return xe_bo_ggtt_addr(dsb_buf->vma->bo);
+ return xe_bo_ggtt_addr(dsb_buf->bo);
}
void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val)
{
- iosys_map_wr(&dsb_buf->vma->bo->vmap, idx * 4, u32, val);
+ iosys_map_wr(&dsb_buf->bo->vmap, idx * 4, u32, val);
}
u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx)
{
- return iosys_map_rd(&dsb_buf->vma->bo->vmap, idx * 4, u32);
+ return iosys_map_rd(&dsb_buf->bo->vmap, idx * 4, u32);
}
void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size)
{
WARN_ON(idx > (dsb_buf->buf_size - size) / sizeof(*dsb_buf->cmd_buf));
- iosys_map_memset(&dsb_buf->vma->bo->vmap, idx * 4, val, size);
+ iosys_map_memset(&dsb_buf->bo->vmap, idx * 4, val, size);
}
-bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, size_t size)
+struct intel_dsb_buffer *intel_dsb_buffer_create(struct drm_device *drm, size_t size)
{
- struct xe_device *xe = to_xe_device(crtc->base.dev);
+ struct xe_device *xe = to_xe_device(drm);
+ struct intel_dsb_buffer *dsb_buf;
struct xe_bo *obj;
- struct i915_vma *vma;
+ int ret;
- vma = kzalloc(sizeof(*vma), GFP_KERNEL);
- if (!vma)
- return false;
+ dsb_buf = kzalloc(sizeof(*dsb_buf), GFP_KERNEL);
+ if (!dsb_buf)
+ return ERR_PTR(-ENOMEM);
/* Set scanout flag for WC mapping */
obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe),
@@ -49,26 +54,30 @@ bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *d
XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
XE_BO_FLAG_SCANOUT | XE_BO_FLAG_GGTT, false);
if (IS_ERR(obj)) {
- kfree(vma);
- return false;
+ ret = PTR_ERR(obj);
+ goto err_pin_map;
}
- vma->bo = obj;
- dsb_buf->vma = vma;
+ dsb_buf->bo = obj;
dsb_buf->buf_size = size;
- return true;
+ return dsb_buf;
+
+err_pin_map:
+ kfree(dsb_buf);
+
+ return ERR_PTR(ret);
}
void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf)
{
- xe_bo_unpin_map_no_vm(dsb_buf->vma->bo);
- kfree(dsb_buf->vma);
+ xe_bo_unpin_map_no_vm(dsb_buf->bo);
+ kfree(dsb_buf);
}
void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf)
{
- struct xe_device *xe = dsb_buf->vma->bo->tile->xe;
+ struct xe_device *xe = dsb_buf->bo->tile->xe;
/*
* The memory barrier here is to ensure coherency of DSB vs MMIO,
diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
index 71d21fde1736..07acae121aa7 100644
--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
@@ -3,18 +3,20 @@
* Copyright 2023, Intel Corporation.
*/
+#include <linux/delay.h>
+
#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
#include <drm/intel/i915_hdcp_interface.h>
-#include <linux/delay.h>
#include "abi/gsc_command_header_abi.h"
-#include "intel_hdcp_gsc.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_force_wake.h"
#include "xe_gsc_proxy.h"
#include "xe_gsc_submit.h"
+#include "xe_hdcp_gsc.h"
#include "xe_map.h"
#include "xe_pm.h"
#include "xe_uc_fw.h"
@@ -30,7 +32,7 @@ struct intel_hdcp_gsc_context {
#define HDCP_GSC_HEADER_SIZE sizeof(struct intel_gsc_mtl_header)
-bool intel_hdcp_gsc_check_status(struct drm_device *drm)
+static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
@@ -87,7 +89,7 @@ out:
return ret;
}
-struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
+static struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct intel_hdcp_gsc_context *gsc_context;
@@ -111,7 +113,7 @@ struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *d
return gsc_context;
}
-void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
+static void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
{
if (!gsc_context)
return;
@@ -146,9 +148,9 @@ static int xe_gsc_send_sync(struct xe_device *xe,
return ret;
}
-ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
- void *msg_in, size_t msg_in_len,
- void *msg_out, size_t msg_out_len)
+static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
+ void *msg_in, size_t msg_in_len,
+ void *msg_out, size_t msg_out_len)
{
struct xe_device *xe = gsc_context->xe;
const size_t max_msg_size = PAGE_SIZE - HDCP_GSC_HEADER_SIZE;
@@ -198,3 +200,10 @@ ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
return ret;
}
+
+const struct intel_display_hdcp_interface xe_display_hdcp_interface = {
+ .gsc_msg_send = intel_hdcp_gsc_msg_send,
+ .gsc_check_status = intel_hdcp_gsc_check_status,
+ .gsc_context_alloc = intel_hdcp_gsc_context_alloc,
+ .gsc_context_free = intel_hdcp_gsc_context_free,
+};
diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.h b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.h
new file mode 100644
index 000000000000..c1062e4b62f7
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __XE_HDCP_GSC_H__
+#define __XE_HDCP_GSC_H__
+
+extern const struct intel_display_hdcp_interface xe_display_hdcp_interface;
+
+#endif
diff --git a/drivers/gpu/drm/xe/display/xe_panic.c b/drivers/gpu/drm/xe/display/xe_panic.c
index df663286092a..e078494dc8ba 100644
--- a/drivers/gpu/drm/xe/display/xe_panic.c
+++ b/drivers/gpu/drm/xe/display/xe_panic.c
@@ -3,11 +3,12 @@
#include <drm/drm_cache.h>
#include <drm/drm_panic.h>
+#include <drm/intel/display_parent_interface.h>
#include "intel_display_types.h"
#include "intel_fb.h"
-#include "intel_panic.h"
#include "xe_bo.h"
+#include "xe_panic.h"
#include "xe_res_cursor.h"
struct intel_panic {
@@ -74,7 +75,7 @@ static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int
iosys_map_wr(&panic->vmap, offset, u32, color);
}
-struct intel_panic *intel_panic_alloc(void)
+static struct intel_panic *xe_panic_alloc(void)
{
struct intel_panic *panic;
@@ -83,7 +84,7 @@ struct intel_panic *intel_panic_alloc(void)
return panic;
}
-int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
+static int xe_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
@@ -96,7 +97,8 @@ int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
return 0;
}
-void intel_panic_finish(struct intel_panic *panic)
-{
- xe_panic_kunmap(panic);
-}
+const struct intel_display_panic_interface xe_display_panic_interface = {
+ .alloc = xe_panic_alloc,
+ .setup = xe_panic_setup,
+ .finish = xe_panic_kunmap,
+};
diff --git a/drivers/gpu/drm/xe/display/xe_panic.h b/drivers/gpu/drm/xe/display/xe_panic.h
new file mode 100644
index 000000000000..3054b511011b
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_panic.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __XE_PANIC_H__
+#define __XE_PANIC_H__
+
+extern const struct intel_display_panic_interface xe_display_panic_interface;
+
+#endif
diff --git a/drivers/gpu/drm/xe/display/xe_plane_initial.c b/drivers/gpu/drm/xe/display/xe_plane_initial.c
index 12d25c5290fd..01c105a93bb9 100644
--- a/drivers/gpu/drm/xe/display/xe_plane_initial.c
+++ b/drivers/gpu/drm/xe/display/xe_plane_initial.c
@@ -58,7 +58,7 @@ intel_reuse_initial_plane_obj(struct intel_crtc *this,
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
- if (!crtc_state->uapi.active)
+ if (!crtc_state->hw.active)
continue;
if (!plane_state->ggtt_vma)
@@ -290,10 +290,12 @@ void intel_initial_plane_config(struct intel_display *display)
struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc) {
+ const struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
struct intel_initial_plane_config *plane_config =
&plane_configs[crtc->pipe];
- if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
+ if (!crtc_state->hw.active)
continue;
/*
diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c
index 9f04ba36e930..12771709183a 100644
--- a/drivers/gpu/drm/xe/display/xe_stolen.c
+++ b/drivers/gpu/drm/xe/display/xe_stolen.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
-#include "gem/i915_gem_stolen.h"
+#include <drm/intel/display_parent_interface.h>
+
#include "xe_res_cursor.h"
+#include "xe_stolen.h"
#include "xe_ttm_stolen_mgr.h"
#include "xe_validation.h"
@@ -11,8 +13,8 @@ struct intel_stolen_node {
struct xe_bo *bo;
};
-int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
- unsigned int align, u64 start, u64 end)
+static int xe_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
+ unsigned int align, u64 start, u64 end)
{
struct xe_device *xe = node->xe;
@@ -41,33 +43,25 @@ int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 siz
return err;
}
-int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, unsigned int align)
-{
- /* Not used on xe */
- WARN_ON(1);
-
- return -ENODEV;
-}
-
-void i915_gem_stolen_remove_node(struct intel_stolen_node *node)
+static void xe_stolen_remove_node(struct intel_stolen_node *node)
{
xe_bo_unpin_map_no_vm(node->bo);
node->bo = NULL;
}
-bool i915_gem_stolen_initialized(struct drm_device *drm)
+static bool xe_stolen_initialized(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
return ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
}
-bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node)
+static bool xe_stolen_node_allocated(const struct intel_stolen_node *node)
{
return node->bo;
}
-u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node)
+static u64 xe_stolen_node_offset(const struct intel_stolen_node *node)
{
struct xe_res_cursor res;
@@ -75,35 +69,19 @@ u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node)
return res.start;
}
-/* Used for < gen4. These are not supported by Xe */
-u64 i915_gem_stolen_area_address(struct drm_device *drm)
-{
- WARN_ON(1);
-
- return 0;
-}
-
-/* Used for gen9 specific WA. Gen9 is not supported by Xe */
-u64 i915_gem_stolen_area_size(struct drm_device *drm)
-{
- WARN_ON(1);
-
- return 0;
-}
-
-u64 i915_gem_stolen_node_address(struct intel_stolen_node *node)
+static u64 xe_stolen_node_address(const struct intel_stolen_node *node)
{
struct xe_device *xe = node->xe;
- return xe_ttm_stolen_gpu_offset(xe) + i915_gem_stolen_node_offset(node);
+ return xe_ttm_stolen_gpu_offset(xe) + xe_stolen_node_offset(node);
}
-u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node)
+static u64 xe_stolen_node_size(const struct intel_stolen_node *node)
{
return node->bo->ttm.base.size;
}
-struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
+static struct intel_stolen_node *xe_stolen_node_alloc(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct intel_stolen_node *node;
@@ -117,7 +95,19 @@ struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
return node;
}
-void i915_gem_stolen_node_free(const struct intel_stolen_node *node)
+static void xe_stolen_node_free(const struct intel_stolen_node *node)
{
kfree(node);
}
+
+const struct intel_display_stolen_interface xe_display_stolen_interface = {
+ .insert_node_in_range = xe_stolen_insert_node_in_range,
+ .remove_node = xe_stolen_remove_node,
+ .initialized = xe_stolen_initialized,
+ .node_allocated = xe_stolen_node_allocated,
+ .node_offset = xe_stolen_node_offset,
+ .node_address = xe_stolen_node_address,
+ .node_size = xe_stolen_node_size,
+ .node_alloc = xe_stolen_node_alloc,
+ .node_free = xe_stolen_node_free,
+};
diff --git a/drivers/gpu/drm/xe/display/xe_stolen.h b/drivers/gpu/drm/xe/display/xe_stolen.h
new file mode 100644
index 000000000000..db86b9e01242
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_stolen.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2025 Intel Corporation */
+
+#ifndef __XE_STOLEN_H__
+#define __XE_STOLEN_H__
+
+extern const struct intel_display_stolen_interface xe_display_stolen_interface;
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 7d46d5ecda91..a85be9ba175e 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -696,13 +696,6 @@ struct xe_device {
* drm_i915_private during build. After cleanup these should go away,
* migrating to the right sub-structs
*/
- const struct dram_info *dram_info;
-
- /*
- * edram size in MB.
- * Cannot be determined by PCIID. You must always read a register.
- */
- u32 edram_size_mb;
struct intel_uncore {
spinlock_t lock;
diff --git a/drivers/gpu/drm/xe/xe_hw_fence.c b/drivers/gpu/drm/xe/xe_hw_fence.c
index b2a0c46dfcd4..f6057456e460 100644
--- a/drivers/gpu/drm/xe/xe_hw_fence.c
+++ b/drivers/gpu/drm/xe/xe_hw_fence.c
@@ -85,7 +85,6 @@ void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq)
{
struct xe_hw_fence *fence, *next;
unsigned long flags;
- int err;
bool tmp;
if (XE_WARN_ON(!list_empty(&irq->pending))) {
@@ -93,9 +92,8 @@ void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq)
spin_lock_irqsave(&irq->lock, flags);
list_for_each_entry_safe(fence, next, &irq->pending, irq_link) {
list_del_init(&fence->irq_link);
- err = dma_fence_signal_locked(&fence->dma);
+ XE_WARN_ON(dma_fence_check_and_signal_locked(&fence->dma));
dma_fence_put(&fence->dma);
- XE_WARN_ON(err);
}
spin_unlock_irqrestore(&irq->lock, flags);
dma_fence_end_signalling(tmp);