summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Kconfig4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h66
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c227
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c109
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c98
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c147
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c41
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c99
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c117
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c32
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c222
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h50
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_encoders.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/clearstate_si.h (renamed from drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h)0
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.c2320
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.h239
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_smc.c995
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_smumgr.h94
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c22
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v6_0.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c22
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c921
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c34
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/kv_dpm.c66
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c592
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_vi.h55
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si.c982
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dma.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dpm.c151
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_ih.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_smc.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sid.h (renamed from drivers/gpu/drm/amd/include/asic_reg/si/sid.h)0
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_vi.h101
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c38
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c93
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.c164
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.h112
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi_dpm.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vid.h2
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h17
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h8
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h4
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h9
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h6
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_d.h9
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_sh_mask.h6
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h8
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h4
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/si/si_reg.h105
-rw-r--r--drivers/gpu/drm/amd/include/cgs_common.h7
-rw-r--r--drivers/gpu/drm/amd/powerplay/amd_powerplay.c741
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c2
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c9
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c5
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c16
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c123
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c14
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c176
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c8
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c6
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c214
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c226
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c28
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h20
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/eventmgr.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h21
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_debug.h10
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_instance.h5
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smumgr.h19
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c181
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h4
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c6
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c44
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c10
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c32
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c6
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c36
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c14
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c40
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c16
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c32
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c7
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c74
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h2
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c41
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h13
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c92
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h8
-rw-r--r--drivers/gpu/drm/armada/Kconfig2
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c18
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c2
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h6
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c153
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c7
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi.c440
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi.h85
-rw-r--r--drivers/gpu/drm/cirrus/Kconfig9
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c2
-rw-r--r--drivers/gpu/drm/drm_agpsupport.c2
-rw-r--r--drivers/gpu/drm/drm_atomic.c85
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c238
-rw-r--r--drivers/gpu/drm/drm_auth.c4
-rw-r--r--drivers/gpu/drm/drm_blend.c11
-rw-r--r--drivers/gpu/drm/drm_cache.c27
-rw-r--r--drivers/gpu/drm/drm_connector.c21
-rw-r--r--drivers/gpu/drm/drm_crtc.c51
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c28
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h1
-rw-r--r--drivers/gpu/drm/drm_debugfs.c29
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c2
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c6
-rw-r--r--drivers/gpu/drm/drm_drv.c10
-rw-r--r--drivers/gpu/drm/drm_dumb_buffers.c4
-rw-r--r--drivers/gpu/drm/drm_edid.c65
-rw-r--r--drivers/gpu/drm/drm_encoder.c2
-rw-r--r--drivers/gpu/drm/drm_encoder_slave.c2
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c27
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c48
-rw-r--r--drivers/gpu/drm/drm_fops.c11
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c12
-rw-r--r--drivers/gpu/drm/drm_gem.c24
-rw-r--r--drivers/gpu/drm/drm_internal.h1
-rw-r--r--drivers/gpu/drm/drm_irq.c45
-rw-r--r--drivers/gpu/drm/drm_mm.c4
-rw-r--r--drivers/gpu/drm/drm_mode_config.c7
-rw-r--r--drivers/gpu/drm/drm_modes.c27
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c10
-rw-r--r--drivers/gpu/drm/drm_pci.c4
-rw-r--r--drivers/gpu/drm/drm_plane.c2
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c9
-rw-r--r--drivers/gpu/drm/drm_platform.c2
-rw-r--r--drivers/gpu/drm/drm_prime.c19
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c77
-rw-r--r--drivers/gpu/drm/drm_property.c4
-rw-r--r--drivers/gpu/drm/drm_sysfs.c2
-rw-r--r--drivers/gpu/drm/etnaviv/Kconfig3
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.c7
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.c7
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h10
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c6
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c10
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h1
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c24
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c1
-rw-r--r--drivers/gpu/drm/i810/i810_drv.h1
-rw-r--r--drivers/gpu/drm/i915/Makefile2
-rw-r--r--drivers/gpu/drm/i915/gvt/aperture_gm.c69
-rw-r--r--drivers/gpu/drm/i915/gvt/cfg_space.c74
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.c81
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.h1
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.c8
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.h8
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c103
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c14
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.c84
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.h4
-rw-r--r--drivers/gpu/drm/i915/gvt/opregion.c8
-rw-r--r--drivers/gpu/drm/i915/gvt/reg.h3
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.c14
-rw-r--r--drivers/gpu/drm/i915/gvt/vgpu.c162
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c103
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c60
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h71
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c335
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c55
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c39
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c7
-rw-r--r--drivers/gpu/drm/i915/i915_gem_fence_reg.c64
-rw-r--r--drivers/gpu/drm/i915/i915_gem_fence_reg.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c438
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h74
-rw-r--r--drivers/gpu/drm/i915/i915_gem_internal.c8
-rw-r--r--drivers/gpu/drm/i915/i915_gem_object.h23
-rw-r--r--drivers/gpu/drm/i915/i915_gem_render_state.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem_request.c35
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c16
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c347
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c1
-rw-r--r--drivers/gpu/drm/i915/i915_guc_reg.h6
-rw-r--r--drivers/gpu/drm/i915/i915_guc_submission.c603
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c86
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h20
-rw-r--r--drivers/gpu/drm/i915/i915_sw_fence.c1
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h16
-rw-r--r--drivers/gpu/drm/i915/i915_vgpu.c33
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c223
-rw-r--r--drivers/gpu/drm/i915/i915_vma.h41
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c20
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c12
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c210
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c42
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c3
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h15
-rw-r--r--drivers/gpu/drm/i915/intel_engine_cs.c2
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c54
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c7
-rw-r--r--drivers/gpu/drm/i915/intel_guc_fwif.h24
-rw-r--r--drivers/gpu/drm/i915/intel_guc_loader.c214
-rw-r--r--drivers/gpu/drm/i915/intel_guc_log.c658
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c20
-rw-r--r--drivers/gpu/drm/i915/intel_hotplug.c4
-rw-r--r--drivers/gpu/drm/i915/intel_huc.c338
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c34
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.h2
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c3
-rw-r--r--drivers/gpu/drm/i915/intel_pipe_crc.c104
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c203
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c24
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c8
-rw-r--r--drivers/gpu/drm/i915/intel_uc.c26
-rw-r--r--drivers/gpu/drm/i915/intel_uc.h73
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c14
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c9
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.h1
-rw-r--r--drivers/gpu/drm/meson/meson_plane.c3
-rw-r--r--drivers/gpu/drm/meson/meson_venc.c19
-rw-r--r--drivers/gpu/drm/meson/meson_venc_cvbs.c2
-rw-r--r--drivers/gpu/drm/mga/mga_dma.c20
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c37
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c2
-rw-r--r--drivers/gpu/drm/msm/Kconfig1
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c14
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c6
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h4
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c22
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c5
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c18
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c33
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_debugfs.c9
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c8
-rw-r--r--drivers/gpu/drm/qxl/qxl_debugfs.c10
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c69
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h6
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c56
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c11
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c66
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_dp_mst.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c4
-rw-r--r--drivers/gpu/drm/radeon/si.c79
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c72
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c14
-rw-r--r--drivers/gpu/drm/selftests/test-drm_mm.c12
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c48
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c10
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c11
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c11
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c2
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c8
-rw-r--r--drivers/gpu/drm/tegra/drm.c26
-rw-r--r--drivers/gpu/drm/tegra/fb.c7
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c27
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c12
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c127
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c17
-rw-r--r--drivers/gpu/drm/vc4/vc4_debugfs.c6
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h2
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c18
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.h1
-rw-r--r--drivers/gpu/drm/vgem/vgem_fence.c4
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ttm.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c3
-rw-r--r--drivers/gpu/drm/zte/Kconfig2
-rw-r--r--drivers/gpu/drm/zte/Makefile1
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c1
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.h1
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi.c160
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi_regs.h14
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c328
-rw-r--r--drivers/gpu/drm/zte/zx_plane.h12
-rw-r--r--drivers/gpu/drm/zte/zx_plane_regs.h51
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc.c407
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc_regs.h31
-rw-r--r--drivers/gpu/drm/zte/zx_vou.c356
-rw-r--r--drivers/gpu/drm/zte/zx_vou.h48
-rw-r--r--drivers/gpu/drm/zte/zx_vou_regs.h51
341 files changed, 11318 insertions, 9681 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 6f3f9e68c218..90bc65d07a35 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -138,7 +138,7 @@ config DRM_KMS_CMA_HELPER
config DRM_VM
bool
- depends on DRM
+ depends on DRM && MMU
source "drivers/gpu/drm/i2c/Kconfig"
@@ -267,7 +267,7 @@ source "drivers/gpu/drm/meson/Kconfig"
menuconfig DRM_LEGACY
bool "Enable legacy drivers (DANGEROUS)"
- depends on DRM
+ depends on DRM && MMU
select DRM_VM
help
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index 41bd2bf28f4c..2814aad81752 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -24,7 +24,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
- amdgpu_gtt_mgr.o amdgpu_vram_mgr.o
+ amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o
# add asic specific block
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
@@ -34,7 +34,7 @@ amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o
amdgpu-y += \
- vi.o
+ vi.o mxgpu_vi.o
# add GMC block
amdgpu-y += \
@@ -52,8 +52,7 @@ amdgpu-y += \
# add SMC block
amdgpu-y += \
amdgpu_dpm.o \
- amdgpu_powerplay.o \
- cz_smc.o cz_dpm.o
+ amdgpu_powerplay.o
# add DCE block
amdgpu-y += \
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index f4f371fbce16..94a64e3bc682 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -91,7 +91,6 @@ extern int amdgpu_vm_fault_stop;
extern int amdgpu_vm_debug;
extern int amdgpu_sched_jobs;
extern int amdgpu_sched_hw_submission;
-extern int amdgpu_powerplay;
extern int amdgpu_no_evict;
extern int amdgpu_direct_gma_size;
extern unsigned amdgpu_pcie_gen_cap;
@@ -184,12 +183,18 @@ enum amdgpu_thermal_irq {
AMDGPU_THERMAL_IRQ_LAST
};
+enum amdgpu_kiq_irq {
+ AMDGPU_CP_KIQ_IRQ_DRIVER0 = 0,
+ AMDGPU_CP_KIQ_IRQ_LAST
+};
+
int amdgpu_set_clockgating_state(struct amdgpu_device *adev,
enum amd_ip_block_type block_type,
enum amd_clockgating_state state);
int amdgpu_set_powergating_state(struct amdgpu_device *adev,
enum amd_ip_block_type block_type,
enum amd_powergating_state state);
+void amdgpu_get_clockgating_state(struct amdgpu_device *adev, u32 *flags);
int amdgpu_wait_for_idle(struct amdgpu_device *adev,
enum amd_ip_block_type block_type);
bool amdgpu_is_idle(struct amdgpu_device *adev,
@@ -352,7 +357,7 @@ struct amdgpu_bo_va_mapping {
struct list_head list;
struct interval_tree_node it;
uint64_t offset;
- uint32_t flags;
+ uint64_t flags;
};
/* bo virtual addresses in a specific vm */
@@ -776,14 +781,20 @@ struct amdgpu_mec {
u32 num_queue;
};
+struct amdgpu_kiq {
+ u64 eop_gpu_addr;
+ struct amdgpu_bo *eop_obj;
+ struct amdgpu_ring ring;
+ struct amdgpu_irq_src irq;
+};
+
/*
* GPU scratch registers structures, functions & helpers
*/
struct amdgpu_scratch {
unsigned num_reg;
uint32_t reg_base;
- bool free[32];
- uint32_t reg[32];
+ uint32_t free_mask;
};
/*
@@ -851,6 +862,7 @@ struct amdgpu_gfx {
struct amdgpu_gca_config config;
struct amdgpu_rlc rlc;
struct amdgpu_mec mec;
+ struct amdgpu_kiq kiq;
struct amdgpu_scratch scratch;
const struct firmware *me_fw; /* ME firmware */
uint32_t me_fw_version;
@@ -894,8 +906,8 @@ int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib,
struct dma_fence *f);
int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
- struct amdgpu_ib *ib, struct dma_fence *last_vm_update,
- struct amdgpu_job *job, struct dma_fence **f);
+ struct amdgpu_ib *ibs, struct amdgpu_job *job,
+ struct dma_fence **f);
int amdgpu_ib_pool_init(struct amdgpu_device *adev);
void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
@@ -938,6 +950,7 @@ struct amdgpu_cs_parser {
#define AMDGPU_PREAMBLE_IB_PRESENT (1 << 0) /* bit set means command submit involves a preamble IB */
#define AMDGPU_PREAMBLE_IB_PRESENT_FIRST (1 << 1) /* bit set means preamble IB is first presented in belonging context */
#define AMDGPU_HAVE_CTX_SWITCH (1 << 2) /* bit set means context switch occured */
+#define AMDGPU_VM_DOMAIN (1 << 3) /* bit set means in virtual memory context */
struct amdgpu_job {
struct amd_sched_job base;
@@ -1024,6 +1037,7 @@ struct amdgpu_uvd {
bool use_ctx_buf;
struct amd_sched_entity entity;
uint32_t srbm_soft_reset;
+ bool is_powergated;
};
/*
@@ -1052,6 +1066,7 @@ struct amdgpu_vce {
struct amd_sched_entity entity;
uint32_t srbm_soft_reset;
unsigned num_rings;
+ bool is_powergated;
};
/*
@@ -1133,7 +1148,6 @@ int amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
#if defined(CONFIG_DEBUG_FS)
int amdgpu_debugfs_init(struct drm_minor *minor);
-void amdgpu_debugfs_cleanup(struct drm_minor *minor);
#endif
int amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
@@ -1178,7 +1192,6 @@ struct amdgpu_asic_funcs {
bool (*read_disabled_bios)(struct amdgpu_device *adev);
bool (*read_bios_from_rom)(struct amdgpu_device *adev,
u8 *bios, u32 length_bytes);
- void (*detect_hw_virtualization) (struct amdgpu_device *adev);
int (*read_register)(struct amdgpu_device *adev, u32 se_num,
u32 sh_num, u32 reg_offset, u32 *value);
void (*set_vga_state)(struct amdgpu_device *adev, bool state);
@@ -1333,7 +1346,6 @@ struct amdgpu_device {
/* BIOS */
uint8_t *bios;
uint32_t bios_size;
- bool is_atom_bios;
struct amdgpu_bo *stollen_vga_memory;
uint32_t bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
@@ -1463,7 +1475,7 @@ struct amdgpu_device {
/* amdkfd interface */
struct kfd_dev *kfd;
- struct amdgpu_virtualization virtualization;
+ struct amdgpu_virt virt;
/* link all shadow bo */
struct list_head shadow_list;
@@ -1576,6 +1588,37 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
ring->count_dw--;
}
+static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring, void *src, int count_dw)
+{
+ unsigned occupied, chunk1, chunk2;
+ void *dst;
+
+ if (ring->count_dw < count_dw) {
+ DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
+ } else {
+ occupied = ring->wptr & ring->ptr_mask;
+ dst = (void *)&ring->ring[occupied];
+ chunk1 = ring->ptr_mask + 1 - occupied;
+ chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
+ chunk2 = count_dw - chunk1;
+ chunk1 <<= 2;
+ chunk2 <<= 2;
+
+ if (chunk1)
+ memcpy(dst, src, chunk1);
+
+ if (chunk2) {
+ src += chunk1;
+ dst = (void *)ring->ring;
+ memcpy(dst, src, chunk2);
+ }
+
+ ring->wptr += count_dw;
+ ring->wptr &= ring->ptr_mask;
+ ring->count_dw -= count_dw;
+ }
+}
+
static inline struct amdgpu_sdma_instance *
amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
{
@@ -1605,7 +1648,6 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
#define amdgpu_asic_get_gpu_clock_counter(adev) (adev)->asic_funcs->get_gpu_clock_counter((adev))
#define amdgpu_asic_read_disabled_bios(adev) (adev)->asic_funcs->read_disabled_bios((adev))
#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
-#define amdgpu_asic_detect_hw_virtualization(adev) (adev)->asic_funcs->detect_hw_virtualization((adev))
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
#define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
@@ -1627,6 +1669,8 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
#define amdgpu_ring_emit_hdp_invalidate(r) (r)->funcs->emit_hdp_invalidate((r))
#define amdgpu_ring_emit_switch_buffer(r) (r)->funcs->emit_switch_buffer((r))
#define amdgpu_ring_emit_cntxcntl(r, d) (r)->funcs->emit_cntxcntl((r), (d))
+#define amdgpu_ring_emit_rreg(r, d) (r)->funcs->emit_rreg((r), (d))
+#define amdgpu_ring_emit_wreg(r, d, v) (r)->funcs->emit_wreg((r), (d), (v))
#define amdgpu_ring_pad_ib(r, ib) ((r)->funcs->pad_ib((r), (ib)))
#define amdgpu_ring_init_cond_exec(r) (r)->funcs->init_cond_exec((r))
#define amdgpu_ring_patch_cond_exec(r,o) (r)->funcs->patch_cond_exec((r),(o))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 5796539a0bcb..ef79551b4cb7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -672,12 +672,10 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
enc->enc_priv) {
- if (adev->is_atom_bios) {
- struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
- if (dig->bl_dev) {
- atif->encoder_for_bl = enc;
- break;
- }
+ struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
+ if (dig->bl_dev) {
+ atif->encoder_for_bl = enc;
+ break;
}
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 8ec1967a850b..d9def01f276e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -42,6 +42,51 @@
#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
+/* Check if current bios is an ATOM BIOS.
+ * Return true if it is ATOM BIOS. Otherwise, return false.
+ */
+static bool check_atom_bios(uint8_t *bios, size_t size)
+{
+ uint16_t tmp, bios_header_start;
+
+ if (!bios || size < 0x49) {
+ DRM_INFO("vbios mem is null or mem size is wrong\n");
+ return false;
+ }
+
+ if (!AMD_IS_VALID_VBIOS(bios)) {
+ DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]);
+ return false;
+ }
+
+ tmp = bios[0x18] | (bios[0x19] << 8);
+ if (bios[tmp + 0x14] != 0x0) {
+ DRM_INFO("Not an x86 BIOS ROM\n");
+ return false;
+ }
+
+ bios_header_start = bios[0x48] | (bios[0x49] << 8);
+ if (!bios_header_start) {
+ DRM_INFO("Can't locate bios header\n");
+ return false;
+ }
+
+ tmp = bios_header_start + 4;
+ if (size < tmp) {
+ DRM_INFO("BIOS header is broken\n");
+ return false;
+ }
+
+ if (!memcmp(bios + tmp, "ATOM", 4) ||
+ !memcmp(bios + tmp, "MOTA", 4)) {
+ DRM_DEBUG("ATOMBIOS detected\n");
+ return true;
+ }
+
+ return false;
+}
+
+
/* If you boot an IGP board with a discrete card as the primary,
* the IGP rom is not accessible via the rom bar as the IGP rom is
* part of the system bios. On boot, the system bios puts a
@@ -65,10 +110,6 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
return false;
}
- if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
- iounmap(bios);
- return false;
- }
adev->bios = kmalloc(size, GFP_KERNEL);
if (!adev->bios) {
iounmap(bios);
@@ -77,12 +118,18 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
adev->bios_size = size;
memcpy_fromio(adev->bios, bios, size);
iounmap(bios);
+
+ if (!check_atom_bios(adev->bios, size)) {
+ kfree(adev->bios);
+ return false;
+ }
+
return true;
}
bool amdgpu_read_bios(struct amdgpu_device *adev)
{
- uint8_t __iomem *bios, val[2];
+ uint8_t __iomem *bios;
size_t size;
adev->bios = NULL;
@@ -92,13 +139,6 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
return false;
}
- val[0] = readb(&bios[0]);
- val[1] = readb(&bios[1]);
-
- if (size == 0 || !AMD_IS_VALID_VBIOS(val)) {
- pci_unmap_rom(adev->pdev, bios);
- return false;
- }
adev->bios = kzalloc(size, GFP_KERNEL);
if (adev->bios == NULL) {
pci_unmap_rom(adev->pdev, bios);
@@ -107,6 +147,12 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
adev->bios_size = size;
memcpy_fromio(adev->bios, bios, size);
pci_unmap_rom(adev->pdev, bios);
+
+ if (!check_atom_bios(adev->bios, size)) {
+ kfree(adev->bios);
+ return false;
+ }
+
return true;
}
@@ -140,7 +186,14 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
adev->bios_size = len;
/* read complete BIOS */
- return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
+ amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
+
+ if (!check_atom_bios(adev->bios, len)) {
+ kfree(adev->bios);
+ return false;
+ }
+
+ return true;
}
static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
@@ -155,13 +208,17 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
return false;
}
- if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
+ adev->bios = kzalloc(size, GFP_KERNEL);
+ if (adev->bios == NULL)
return false;
- }
- adev->bios = kmemdup(bios, size, GFP_KERNEL);
- if (adev->bios == NULL) {
+
+ memcpy_fromio(adev->bios, bios, size);
+
+ if (!check_atom_bios(adev->bios, size)) {
+ kfree(adev->bios);
return false;
}
+
adev->bios_size = size;
return true;
@@ -273,7 +330,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
break;
}
- if (i == 0 || !AMD_IS_VALID_VBIOS(adev->bios)) {
+ if (!check_atom_bios(adev->bios, size)) {
kfree(adev->bios);
return false;
}
@@ -298,53 +355,59 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
#ifdef CONFIG_ACPI
static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
{
- bool ret = false;
struct acpi_table_header *hdr;
acpi_size tbl_size;
UEFI_ACPI_VFCT *vfct;
- GOP_VBIOS_CONTENT *vbios;
- VFCT_IMAGE_HEADER *vhdr;
+ unsigned offset;
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
- goto out_unmap;
+ return false;
}
vfct = (UEFI_ACPI_VFCT *)hdr;
- if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
- DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
- goto out_unmap;
- }
+ offset = vfct->VBIOSImageOffset;
- vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
- vhdr = &vbios->VbiosHeader;
- DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
- vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
- vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
-
- if (vhdr->PCIBus != adev->pdev->bus->number ||
- vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
- vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) ||
- vhdr->VendorID != adev->pdev->vendor ||
- vhdr->DeviceID != adev->pdev->device) {
- DRM_INFO("ACPI VFCT table is not for this card\n");
- goto out_unmap;
- }
+ while (offset < tbl_size) {
+ GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
+ VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
- if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
- DRM_ERROR("ACPI VFCT image truncated\n");
- goto out_unmap;
- }
+ offset += sizeof(VFCT_IMAGE_HEADER);
+ if (offset > tbl_size) {
+ DRM_ERROR("ACPI VFCT image header truncated\n");
+ return false;
+ }
+
+ offset += vhdr->ImageLength;
+ if (offset > tbl_size) {
+ DRM_ERROR("ACPI VFCT image truncated\n");
+ return false;
+ }
- adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
- adev->bios_size = vhdr->ImageLength;
- ret = !!adev->bios;
+ if (vhdr->ImageLength &&
+ vhdr->PCIBus == adev->pdev->bus->number &&
+ vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
+ vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
+ vhdr->VendorID == adev->pdev->vendor &&
+ vhdr->DeviceID == adev->pdev->device) {
+ adev->bios = kmemdup(&vbios->VbiosContent,
+ vhdr->ImageLength,
+ GFP_KERNEL);
+
+ if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {
+ kfree(adev->bios);
+ return false;
+ }
+ adev->bios_size = vhdr->ImageLength;
+ return true;
+ }
+ }
-out_unmap:
- return ret;
+ DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
+ return false;
}
#else
static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
@@ -355,57 +418,27 @@ static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
bool amdgpu_get_bios(struct amdgpu_device *adev)
{
- bool r;
- uint16_t tmp, bios_header_start;
+ if (amdgpu_atrm_get_bios(adev))
+ return true;
- r = amdgpu_atrm_get_bios(adev);
- if (!r)
- r = amdgpu_acpi_vfct_bios(adev);
- if (!r)
- r = igp_read_bios_from_vram(adev);
- if (!r)
- r = amdgpu_read_bios(adev);
- if (!r) {
- r = amdgpu_read_bios_from_rom(adev);
- }
- if (!r) {
- r = amdgpu_read_disabled_bios(adev);
- }
- if (!r) {
- r = amdgpu_read_platform_bios(adev);
- }
- if (!r || adev->bios == NULL) {
- DRM_ERROR("Unable to locate a BIOS ROM\n");
- adev->bios = NULL;
- return false;
- }
- if (!AMD_IS_VALID_VBIOS(adev->bios)) {
- printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
- goto free_bios;
- }
+ if (amdgpu_acpi_vfct_bios(adev))
+ return true;
- tmp = RBIOS16(0x18);
- if (RBIOS8(tmp + 0x14) != 0x0) {
- DRM_INFO("Not an x86 BIOS ROM, not using.\n");
- goto free_bios;
- }
+ if (igp_read_bios_from_vram(adev))
+ return true;
- bios_header_start = RBIOS16(0x48);
- if (!bios_header_start) {
- goto free_bios;
- }
- tmp = bios_header_start + 4;
- if (!memcmp(adev->bios + tmp, "ATOM", 4) ||
- !memcmp(adev->bios + tmp, "MOTA", 4)) {
- adev->is_atom_bios = true;
- } else {
- adev->is_atom_bios = false;
- }
+ if (amdgpu_read_bios(adev))
+ return true;
- DRM_DEBUG("%sBIOS detected\n", adev->is_atom_bios ? "ATOM" : "COM");
- return true;
-free_bios:
- kfree(adev->bios);
- adev->bios = NULL;
+ if (amdgpu_read_bios_from_rom(adev))
+ return true;
+
+ if (amdgpu_read_disabled_bios(adev))
+ return true;
+
+ if (amdgpu_read_platform_bios(adev))
+ return true;
+
+ DRM_ERROR("Unable to locate a BIOS ROM\n");
return false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index 9ada56c16a58..a5df1ef306d9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -713,6 +713,7 @@ static int amdgpu_cgs_rel_firmware(struct cgs_device *cgs_device, enum cgs_ucode
CGS_FUNC_ADEV;
if ((CGS_UCODE_ID_SMU == type) || (CGS_UCODE_ID_SMU_SK == type)) {
release_firmware(adev->pm.fw);
+ adev->pm.fw = NULL;
return 0;
}
/* cannot release other firmware because they are not created by cgs */
@@ -762,6 +763,23 @@ static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
return fw_version;
}
+static int amdgpu_cgs_enter_safe_mode(struct cgs_device *cgs_device,
+ bool en)
+{
+ CGS_FUNC_ADEV;
+
+ if (adev->gfx.rlc.funcs->enter_safe_mode == NULL ||
+ adev->gfx.rlc.funcs->exit_safe_mode == NULL)
+ return 0;
+
+ if (en)
+ adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ else
+ adev->gfx.rlc.funcs->exit_safe_mode(adev);
+
+ return 0;
+}
+
static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
enum cgs_ucode_id type,
struct cgs_firmware_info *info)
@@ -808,6 +826,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
const uint8_t *src;
const struct smc_firmware_header_v1_0 *hdr;
+ if (CGS_UCODE_ID_SMU_SK == type)
+ amdgpu_cgs_rel_firmware(cgs_device, CGS_UCODE_ID_SMU);
+
if (!adev->pm.fw) {
switch (adev->asic_type) {
case CHIP_TOPAZ:
@@ -840,6 +861,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
else if (type == CGS_UCODE_ID_SMU_SK)
strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin");
break;
+ case CHIP_POLARIS12:
+ strcpy(fw_name, "amdgpu/polaris12_smc.bin");
+ break;
default:
DRM_ERROR("SMC firmware not supported\n");
return -EINVAL;
@@ -1197,51 +1221,52 @@ static int amdgpu_cgs_call_acpi_method(struct cgs_device *cgs_device,
}
static const struct cgs_ops amdgpu_cgs_ops = {
- amdgpu_cgs_gpu_mem_info,
- amdgpu_cgs_gmap_kmem,
- amdgpu_cgs_gunmap_kmem,
- amdgpu_cgs_alloc_gpu_mem,
- amdgpu_cgs_free_gpu_mem,
- amdgpu_cgs_gmap_gpu_mem,
- amdgpu_cgs_gunmap_gpu_mem,
- amdgpu_cgs_kmap_gpu_mem,
- amdgpu_cgs_kunmap_gpu_mem,
- amdgpu_cgs_read_register,
- amdgpu_cgs_write_register,
- amdgpu_cgs_read_ind_register,
- amdgpu_cgs_write_ind_register,
- amdgpu_cgs_read_pci_config_byte,
- amdgpu_cgs_read_pci_config_word,
- amdgpu_cgs_read_pci_config_dword,
- amdgpu_cgs_write_pci_config_byte,
- amdgpu_cgs_write_pci_config_word,
- amdgpu_cgs_write_pci_config_dword,
- amdgpu_cgs_get_pci_resource,
- amdgpu_cgs_atom_get_data_table,
- amdgpu_cgs_atom_get_cmd_table_revs,
- amdgpu_cgs_atom_exec_cmd_table,
- amdgpu_cgs_create_pm_request,
- amdgpu_cgs_destroy_pm_request,
- amdgpu_cgs_set_pm_request,
- amdgpu_cgs_pm_request_clock,
- amdgpu_cgs_pm_request_engine,
- amdgpu_cgs_pm_query_clock_limits,
- amdgpu_cgs_set_camera_voltages,
- amdgpu_cgs_get_firmware_info,
- amdgpu_cgs_rel_firmware,
- amdgpu_cgs_set_powergating_state,
- amdgpu_cgs_set_clockgating_state,
- amdgpu_cgs_get_active_displays_info,
- amdgpu_cgs_notify_dpm_enabled,
- amdgpu_cgs_call_acpi_method,
- amdgpu_cgs_query_system_info,
- amdgpu_cgs_is_virtualization_enabled
+ .gpu_mem_info = amdgpu_cgs_gpu_mem_info,
+ .gmap_kmem = amdgpu_cgs_gmap_kmem,
+ .gunmap_kmem = amdgpu_cgs_gunmap_kmem,
+ .alloc_gpu_mem = amdgpu_cgs_alloc_gpu_mem,
+ .free_gpu_mem = amdgpu_cgs_free_gpu_mem,
+ .gmap_gpu_mem = amdgpu_cgs_gmap_gpu_mem,
+ .gunmap_gpu_mem = amdgpu_cgs_gunmap_gpu_mem,
+ .kmap_gpu_mem = amdgpu_cgs_kmap_gpu_mem,
+ .kunmap_gpu_mem = amdgpu_cgs_kunmap_gpu_mem,
+ .read_register = amdgpu_cgs_read_register,
+ .write_register = amdgpu_cgs_write_register,
+ .read_ind_register = amdgpu_cgs_read_ind_register,
+ .write_ind_register = amdgpu_cgs_write_ind_register,
+ .read_pci_config_byte = amdgpu_cgs_read_pci_config_byte,
+ .read_pci_config_word = amdgpu_cgs_read_pci_config_word,
+ .read_pci_config_dword = amdgpu_cgs_read_pci_config_dword,
+ .write_pci_config_byte = amdgpu_cgs_write_pci_config_byte,
+ .write_pci_config_word = amdgpu_cgs_write_pci_config_word,
+ .write_pci_config_dword = amdgpu_cgs_write_pci_config_dword,
+ .get_pci_resource = amdgpu_cgs_get_pci_resource,
+ .atom_get_data_table = amdgpu_cgs_atom_get_data_table,
+ .atom_get_cmd_table_revs = amdgpu_cgs_atom_get_cmd_table_revs,
+ .atom_exec_cmd_table = amdgpu_cgs_atom_exec_cmd_table,
+ .create_pm_request = amdgpu_cgs_create_pm_request,
+ .destroy_pm_request = amdgpu_cgs_destroy_pm_request,
+ .set_pm_request = amdgpu_cgs_set_pm_request,
+ .pm_request_clock = amdgpu_cgs_pm_request_clock,
+ .pm_request_engine = amdgpu_cgs_pm_request_engine,
+ .pm_query_clock_limits = amdgpu_cgs_pm_query_clock_limits,
+ .set_camera_voltages = amdgpu_cgs_set_camera_voltages,
+ .get_firmware_info = amdgpu_cgs_get_firmware_info,
+ .rel_firmware = amdgpu_cgs_rel_firmware,
+ .set_powergating_state = amdgpu_cgs_set_powergating_state,
+ .set_clockgating_state = amdgpu_cgs_set_clockgating_state,
+ .get_active_displays_info = amdgpu_cgs_get_active_displays_info,
+ .notify_dpm_enabled = amdgpu_cgs_notify_dpm_enabled,
+ .call_acpi_method = amdgpu_cgs_call_acpi_method,
+ .query_system_info = amdgpu_cgs_query_system_info,
+ .is_virtualization_enabled = amdgpu_cgs_is_virtualization_enabled,
+ .enter_safe_mode = amdgpu_cgs_enter_safe_mode,
};
static const struct cgs_os_ops amdgpu_cgs_os_ops = {
- amdgpu_cgs_add_irq_source,
- amdgpu_cgs_irq_get,
- amdgpu_cgs_irq_put
+ .add_irq_source = amdgpu_cgs_add_irq_source,
+ .irq_get = amdgpu_cgs_irq_get,
+ .irq_put = amdgpu_cgs_irq_put
};
struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 29d6d84d1c28..cf2e8c4e9b8b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -75,10 +75,10 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
*out_ring = &adev->uvd.ring;
break;
case AMDGPU_HW_IP_VCE:
- if (ring < 2){
+ if (ring < adev->vce.num_rings){
*out_ring = &adev->vce.ring[ring];
} else {
- DRM_ERROR("only two VCE rings are supported\n");
+ DRM_ERROR("only %d VCE rings are supported\n", adev->vce.num_rings);
return -EINVAL;
}
break;
@@ -771,6 +771,20 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
if (r)
return r;
+ if (amdgpu_sriov_vf(adev)) {
+ struct dma_fence *f;
+ bo_va = vm->csa_bo_va;
+ BUG_ON(!bo_va);
+ r = amdgpu_vm_bo_update(adev, bo_va, false);
+ if (r)
+ return r;
+
+ f = bo_va->last_pt_update;
+ r = amdgpu_sync_fence(adev, &p->job->sync, f);
+ if (r)
+ return r;
+ }
+
if (p->bo_list) {
for (i = 0; i < p->bo_list->num_entries; i++) {
struct dma_fence *f;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 60bd4afe45c8..944ba0d3874a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -73,6 +73,7 @@ static const char *amdgpu_asic_name[] = {
"STONEY",
"POLARIS10",
"POLARIS11",
+ "POLARIS12",
"LAST",
};
@@ -93,6 +94,11 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
{
uint32_t ret;
+ if (amdgpu_sriov_runtime(adev)) {
+ BUG_ON(in_interrupt());
+ return amdgpu_virt_kiq_rreg(adev, reg);
+ }
+
if ((reg * 4) < adev->rmmio_size && !always_indirect)
ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
else {
@@ -112,6 +118,11 @@ void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
{
trace_amdgpu_mm_wreg(adev->pdev->device, reg, v);
+ if (amdgpu_sriov_runtime(adev)) {
+ BUG_ON(in_interrupt());
+ return amdgpu_virt_kiq_wreg(adev, reg, v);
+ }
+
if ((reg * 4) < adev->rmmio_size && !always_indirect)
writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
else {
@@ -884,7 +895,7 @@ static int amdgpu_atombios_init(struct amdgpu_device *adev)
atom_card_info->ioreg_read = cail_ioreg_read;
atom_card_info->ioreg_write = cail_ioreg_write;
} else {
- DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n");
+ DRM_INFO("PCI I/O BAR is not found. Using MMIO to access ATOM BIOS\n");
atom_card_info->ioreg_read = cail_reg_read;
atom_card_info->ioreg_write = cail_reg_write;
}
@@ -1130,6 +1141,18 @@ int amdgpu_set_powergating_state(struct amdgpu_device *adev,
return r;
}
+void amdgpu_get_clockgating_state(struct amdgpu_device *adev, u32 *flags)
+{
+ int i;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_blocks[i].status.valid)
+ continue;
+ if (adev->ip_blocks[i].version->funcs->get_clockgating_state)
+ adev->ip_blocks[i].version->funcs->get_clockgating_state((void *)adev, flags);
+ }
+}
+
int amdgpu_wait_for_idle(struct amdgpu_device *adev,
enum amd_ip_block_type block_type)
{
@@ -1234,7 +1257,8 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
pciaddstr_tmp = pciaddstr;
while ((pciaddname_tmp = strsep(&pciaddstr_tmp, ";"))) {
pciaddname = strsep(&pciaddname_tmp, ",");
- if (!strcmp(pci_address_name, pciaddname)) {
+ if (!strcmp("all", pciaddname)
+ || !strcmp(pci_address_name, pciaddname)) {
long num_crtc;
int res = -1;
@@ -1277,6 +1301,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
case CHIP_FIJI:
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_CARRIZO:
case CHIP_STONEY:
if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY)
@@ -1321,6 +1346,12 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
return -EINVAL;
}
+ if (amdgpu_sriov_vf(adev)) {
+ r = amdgpu_virt_request_full_gpu(adev, true);
+ if (r)
+ return r;
+ }
+
for (i = 0; i < adev->num_ip_blocks; i++) {
if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
DRM_ERROR("disabled ip block: %d\n", i);
@@ -1381,6 +1412,15 @@ static int amdgpu_init(struct amdgpu_device *adev)
return r;
}
adev->ip_blocks[i].status.hw = true;
+
+ /* right after GMC hw init, we create CSA */
+ if (amdgpu_sriov_vf(adev)) {
+ r = amdgpu_allocate_static_csa(adev);
+ if (r) {
+ DRM_ERROR("allocate CSA failed %d\n", r);
+ return r;
+ }
+ }
}
}
@@ -1514,6 +1554,11 @@ static int amdgpu_fini(struct amdgpu_device *adev)
adev->ip_blocks[i].status.late_initialized = false;
}
+ if (amdgpu_sriov_vf(adev)) {
+ amdgpu_bo_free_kernel(&adev->virt.csa_obj, &adev->virt.csa_vmid0_addr, NULL);
+ amdgpu_virt_release_full_gpu(adev, false);
+ }
+
return 0;
}
@@ -1521,6 +1566,9 @@ int amdgpu_suspend(struct amdgpu_device *adev)
{
int i, r;
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_virt_request_full_gpu(adev, false);
+
/* ungate SMC block first */
r = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC,
AMD_CG_STATE_UNGATE);
@@ -1549,6 +1597,9 @@ int amdgpu_suspend(struct amdgpu_device *adev)
}
}
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_virt_release_full_gpu(adev, false);
+
return 0;
}
@@ -1573,7 +1624,7 @@ static int amdgpu_resume(struct amdgpu_device *adev)
static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
{
if (amdgpu_atombios_has_gpu_virtualization_table(adev))
- adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
+ adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
}
/**
@@ -1603,7 +1654,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
adev->pdev = pdev;
adev->flags = flags;
adev->asic_type = flags & AMD_ASIC_MASK;
- adev->is_atom_bios = false;
adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT;
adev->mc.gtt_size = 512 * 1024 * 1024;
adev->accel_working = false;
@@ -1693,7 +1743,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
}
}
if (adev->rio_mem == NULL)
- DRM_ERROR("Unable to find PCI I/O BAR\n");
+ DRM_INFO("PCI I/O BAR is not found.\n");
/* early init functions */
r = amdgpu_early_init(adev);
@@ -1718,12 +1768,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
r = -EINVAL;
goto failed;
}
- /* Must be an ATOMBIOS */
- if (!adev->is_atom_bios) {
- dev_err(adev->dev, "Expecting atombios for GPU\n");
- r = -EINVAL;
- goto failed;
- }
+
r = amdgpu_atombios_init(adev);
if (r) {
dev_err(adev->dev, "amdgpu_atombios_init failed\n");
@@ -1850,8 +1895,6 @@ failed:
return r;
}
-static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev);
-
/**
* amdgpu_device_fini - tear down the driver
*
@@ -1891,7 +1934,6 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
if (adev->asic_type >= CHIP_BONAIRE)
amdgpu_doorbell_fini(adev);
amdgpu_debugfs_regs_cleanup(adev);
- amdgpu_debugfs_remove_files(adev);
}
@@ -2250,6 +2292,9 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
int resched;
bool need_full_reset;
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
if (!amdgpu_check_soft_reset(adev)) {
DRM_INFO("No hardware hang detected. Did some blocks stall?\n");
return 0;
@@ -2505,19 +2550,6 @@ int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
return 0;
}
-static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev)
-{
-#if defined(CONFIG_DEBUG_FS)
- unsigned i;
-
- for (i = 0; i < adev->debugfs_count; i++) {
- drm_debugfs_remove_files(adev->debugfs[i].files,
- adev->debugfs[i].num_files,
- adev->ddev->primary);
- }
-#endif
-}
-
#if defined(CONFIG_DEBUG_FS)
static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
@@ -2851,7 +2883,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
return -ENOMEM;
/* version, increment each time something is added */
- config[no_regs++] = 2;
+ config[no_regs++] = 3;
config[no_regs++] = adev->gfx.config.max_shader_engines;
config[no_regs++] = adev->gfx.config.max_tile_pipes;
config[no_regs++] = adev->gfx.config.max_cu_per_sh;
@@ -2885,6 +2917,12 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
config[no_regs++] = adev->family;
config[no_regs++] = adev->external_rev_id;
+ /* rev==3 */
+ config[no_regs++] = adev->pdev->device;
+ config[no_regs++] = adev->pdev->revision;
+ config[no_regs++] = adev->pdev->subsystem_device;
+ config[no_regs++] = adev->pdev->subsystem_vendor;
+
while (size && (*pos < no_regs * 4)) {
uint32_t value;
@@ -3151,10 +3189,6 @@ int amdgpu_debugfs_init(struct drm_minor *minor)
{
return 0;
}
-
-void amdgpu_debugfs_cleanup(struct drm_minor *minor)
-{
-}
#else
static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index d2036df145b3..39fc388f222a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -138,10 +138,52 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
kfree(work);
}
-int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event,
- uint32_t page_flip_flags, uint32_t target)
+
+static void amdgpu_flip_work_cleanup(struct amdgpu_flip_work *work)
+{
+ int i;
+
+ amdgpu_bo_unref(&work->old_abo);
+ dma_fence_put(work->excl);
+ for (i = 0; i < work->shared_count; ++i)
+ dma_fence_put(work->shared[i]);
+ kfree(work->shared);
+ kfree(work);
+}
+
+static void amdgpu_flip_cleanup_unreserve(struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo)
+{
+ amdgpu_bo_unreserve(new_abo);
+ amdgpu_flip_work_cleanup(work);
+}
+
+static void amdgpu_flip_cleanup_unpin(struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo)
+{
+ if (unlikely(amdgpu_bo_unpin(new_abo) != 0))
+ DRM_ERROR("failed to unpin new abo in error path\n");
+ amdgpu_flip_cleanup_unreserve(work, new_abo);
+}
+
+void amdgpu_crtc_cleanup_flip_ctx(struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo)
+{
+ if (unlikely(amdgpu_bo_reserve(new_abo, false) != 0)) {
+ DRM_ERROR("failed to reserve new abo in error path\n");
+ amdgpu_flip_work_cleanup(work);
+ return;
+ }
+ amdgpu_flip_cleanup_unpin(work, new_abo);
+}
+
+int amdgpu_crtc_prepare_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags,
+ uint32_t target,
+ struct amdgpu_flip_work **work_p,
+ struct amdgpu_bo **new_abo_p)
{
struct drm_device *dev = crtc->dev;
struct amdgpu_device *adev = dev->dev_private;
@@ -154,7 +196,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
unsigned long flags;
u64 tiling_flags;
u64 base;
- int i, r;
+ int r;
work = kzalloc(sizeof *work, GFP_KERNEL);
if (work == NULL)
@@ -189,7 +231,6 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
r = amdgpu_bo_pin(new_abo, AMDGPU_GEM_DOMAIN_VRAM, &base);
if (unlikely(r != 0)) {
- r = -EINVAL;
DRM_ERROR("failed to pin new abo buffer before flip\n");
goto unreserve;
}
@@ -216,41 +257,79 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
r = -EBUSY;
goto pflip_cleanup;
+
}
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+ *work_p = work;
+ *new_abo_p = new_abo;
+
+ return 0;
+
+pflip_cleanup:
+ amdgpu_crtc_cleanup_flip_ctx(work, new_abo);
+ return r;
+unpin:
+ amdgpu_flip_cleanup_unpin(work, new_abo);
+ return r;
+
+unreserve:
+ amdgpu_flip_cleanup_unreserve(work, new_abo);
+ return r;
+
+cleanup:
+ amdgpu_flip_work_cleanup(work);
+ return r;
+
+}
+
+void amdgpu_crtc_submit_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo)
+{
+ unsigned long flags;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING;
amdgpu_crtc->pflip_works = work;
-
- DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_PENDING, work: %p,\n",
- amdgpu_crtc->crtc_id, amdgpu_crtc, work);
/* update crtc fb */
crtc->primary->fb = fb;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+ DRM_DEBUG_DRIVER(
+ "crtc:%d[%p], pflip_stat:AMDGPU_FLIP_PENDING, work: %p,\n",
+ amdgpu_crtc->crtc_id, amdgpu_crtc, work);
+
amdgpu_flip_work_func(&work->flip_work.work);
- return 0;
+}
-pflip_cleanup:
- if (unlikely(amdgpu_bo_reserve(new_abo, false) != 0)) {
- DRM_ERROR("failed to reserve new abo in error path\n");
- goto cleanup;
- }
-unpin:
- if (unlikely(amdgpu_bo_unpin(new_abo) != 0)) {
- DRM_ERROR("failed to unpin new abo in error path\n");
- }
-unreserve:
- amdgpu_bo_unreserve(new_abo);
+int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags,
+ uint32_t target)
+{
+ struct amdgpu_bo *new_abo;
+ struct amdgpu_flip_work *work;
+ int r;
-cleanup:
- amdgpu_bo_unref(&work->old_abo);
- dma_fence_put(work->excl);
- for (i = 0; i < work->shared_count; ++i)
- dma_fence_put(work->shared[i]);
- kfree(work->shared);
- kfree(work);
+ r = amdgpu_crtc_prepare_flip(crtc,
+ fb,
+ event,
+ page_flip_flags,
+ target,
+ &work,
+ &new_abo);
+ if (r)
+ return r;
- return r;
+ amdgpu_crtc_submit_flip(crtc, fb, work, new_abo);
+
+ return 0;
}
int amdgpu_crtc_set_config(struct drm_mode_set *set)
@@ -582,12 +661,10 @@ int amdgpu_modeset_create_props(struct amdgpu_device *adev)
{
int sz;
- if (adev->is_atom_bios) {
- adev->mode_info.coherent_mode_property =
- drm_property_create_range(adev->ddev, 0 , "coherent", 0, 1);
- if (!adev->mode_info.coherent_mode_property)
- return -ENOMEM;
- }
+ adev->mode_info.coherent_mode_property =
+ drm_property_create_range(adev->ddev, 0 , "coherent", 0, 1);
+ if (!adev->mode_info.coherent_mode_property)
+ return -ENOMEM;
adev->mode_info.load_detect_property =
drm_property_create_range(adev->ddev, 0, "load detection", 0, 1);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
index 955d6f21e2b3..fa2b55681422 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
@@ -241,13 +241,6 @@ enum amdgpu_pcie_gen {
AMDGPU_PCIE_GEN_INVALID = 0xffff
};
-enum amdgpu_dpm_forced_level {
- AMDGPU_DPM_FORCED_LEVEL_AUTO = 0,
- AMDGPU_DPM_FORCED_LEVEL_LOW = 1,
- AMDGPU_DPM_FORCED_LEVEL_HIGH = 2,
- AMDGPU_DPM_FORCED_LEVEL_MANUAL = 3,
-};
-
struct amdgpu_dpm_funcs {
int (*get_temperature)(struct amdgpu_device *adev);
int (*pre_set_power_state)(struct amdgpu_device *adev);
@@ -258,7 +251,7 @@ struct amdgpu_dpm_funcs {
u32 (*get_mclk)(struct amdgpu_device *adev, bool low);
void (*print_power_state)(struct amdgpu_device *adev, struct amdgpu_ps *ps);
void (*debugfs_print_current_performance_level)(struct amdgpu_device *adev, struct seq_file *m);
- int (*force_performance_level)(struct amdgpu_device *adev, enum amdgpu_dpm_forced_level level);
+ int (*force_performance_level)(struct amdgpu_device *adev, enum amd_dpm_forced_level level);
bool (*vblank_too_short)(struct amdgpu_device *adev);
void (*powergate_uvd)(struct amdgpu_device *adev, bool gate);
void (*powergate_vce)(struct amdgpu_device *adev, bool gate);
@@ -353,9 +346,6 @@ struct amdgpu_dpm_funcs {
#define amdgpu_dpm_get_current_power_state(adev) \
(adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)
-#define amdgpu_dpm_get_performance_level(adev) \
- (adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle)
-
#define amdgpu_dpm_get_pp_num_states(adev, data) \
(adev)->powerplay.pp_funcs->get_pp_num_states((adev)->powerplay.pp_handle, data)
@@ -393,6 +383,11 @@ struct amdgpu_dpm_funcs {
(adev)->powerplay.pp_funcs->get_vce_clock_state((adev)->powerplay.pp_handle, (i)) : \
(adev)->pm.funcs->get_vce_clock_state((adev), (i)))
+#define amdgpu_dpm_get_performance_level(adev) \
+ ((adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle) : \
+ (adev)->pm.dpm.forced_level)
+
struct amdgpu_dpm {
struct amdgpu_ps *ps;
/* number of valid power states */
@@ -440,7 +435,7 @@ struct amdgpu_dpm {
/* thermal handling */
struct amdgpu_dpm_thermal thermal;
/* forced levels */
- enum amdgpu_dpm_forced_level forced_level;
+ enum amd_dpm_forced_level forced_level;
};
struct amdgpu_pm {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 8cb937b2bfcc..75fc376ba735 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -90,7 +90,6 @@ int amdgpu_vram_page_split = 1024;
int amdgpu_exp_hw_support = 0;
int amdgpu_sched_jobs = 32;
int amdgpu_sched_hw_submission = 2;
-int amdgpu_powerplay = -1;
int amdgpu_no_evict = 0;
int amdgpu_direct_gma_size = 0;
unsigned amdgpu_pcie_gen_cap = 0;
@@ -179,9 +178,6 @@ module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)");
module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
-MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 = auto (default))");
-module_param_named(powerplay, amdgpu_powerplay, int, 0444);
-
MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))");
module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, int, 0444);
@@ -418,6 +414,13 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
+ /* Polaris12 */
+ {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0, 0, 0}
};
@@ -679,7 +682,6 @@ static struct drm_driver kms_driver = {
DRIVER_USE_AGP |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET,
- .dev_priv_size = 0,
.load = amdgpu_driver_load_kms,
.open = amdgpu_driver_open_kms,
.preclose = amdgpu_driver_preclose_kms,
@@ -694,7 +696,6 @@ static struct drm_driver kms_driver = {
.get_scanout_position = amdgpu_get_crtc_scanoutpos,
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = amdgpu_debugfs_init,
- .debugfs_cleanup = amdgpu_debugfs_cleanup,
#endif
.irq_preinstall = amdgpu_irq_preinstall,
.irq_postinstall = amdgpu_irq_postinstall,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index cd62f6ffde2a..9bd1b4eae32e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -471,12 +471,15 @@ out:
static int amdgpu_gem_va_check(void *param, struct amdgpu_bo *bo)
{
- unsigned domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
-
/* if anything is swapped out don't swap it in here,
just abort and wait for the next CS */
+ if (!amdgpu_bo_gpu_accessible(bo))
+ return -ERESTARTSYS;
+
+ if (bo->shadow && !amdgpu_bo_gpu_accessible(bo->shadow))
+ return -ERESTARTSYS;
- return domain == AMDGPU_GEM_DOMAIN_CPU ? -ERESTARTSYS : 0;
+ return 0;
}
/**
@@ -496,7 +499,6 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_bo_list_entry vm_pd;
struct ww_acquire_ctx ticket;
struct list_head list, duplicates;
- unsigned domain;
int r;
INIT_LIST_HEAD(&list);
@@ -514,12 +516,18 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
goto error_print;
list_for_each_entry(entry, &list, head) {
- domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
+ struct amdgpu_bo *bo =
+ container_of(entry->bo, struct amdgpu_bo, tbo);
+
/* if anything is swapped out don't swap it in here,
just abort and wait for the next CS */
- if (domain == AMDGPU_GEM_DOMAIN_CPU)
+ if (!amdgpu_bo_gpu_accessible(bo))
+ goto error_unreserve;
+
+ if (bo->shadow && !amdgpu_bo_gpu_accessible(bo->shadow))
goto error_unreserve;
}
+
r = amdgpu_vm_validate_pt_bos(adev, bo_va->vm, amdgpu_gem_va_check,
NULL);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 01a42b6a69a4..19943356cca7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -42,12 +42,12 @@ int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg)
{
int i;
- for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
- if (adev->gfx.scratch.free[i]) {
- adev->gfx.scratch.free[i] = false;
- *reg = adev->gfx.scratch.reg[i];
- return 0;
- }
+ i = ffs(adev->gfx.scratch.free_mask);
+ if (i != 0 && i <= adev->gfx.scratch.num_reg) {
+ i--;
+ adev->gfx.scratch.free_mask &= ~(1u << i);
+ *reg = adev->gfx.scratch.reg_base + i;
+ return 0;
}
return -EINVAL;
}
@@ -62,14 +62,7 @@ int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg)
*/
void amdgpu_gfx_scratch_free(struct amdgpu_device *adev, uint32_t reg)
{
- int i;
-
- for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
- if (adev->gfx.scratch.reg[i] == reg) {
- adev->gfx.scratch.free[i] = true;
- return;
- }
- }
+ adev->gfx.scratch.free_mask |= 1u << (reg - adev->gfx.scratch.reg_base);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index c6c125d31161..e4eb6dd3798a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -243,9 +243,9 @@ static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
}
const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = {
- amdgpu_gtt_mgr_init,
- amdgpu_gtt_mgr_fini,
- amdgpu_gtt_mgr_new,
- amdgpu_gtt_mgr_del,
- amdgpu_gtt_mgr_debug
+ .init = amdgpu_gtt_mgr_init,
+ .takedown = amdgpu_gtt_mgr_fini,
+ .get_node = amdgpu_gtt_mgr_new,
+ .put_node = amdgpu_gtt_mgr_del,
+ .debug = amdgpu_gtt_mgr_debug
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
index 91d367399956..f2739995c335 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
@@ -231,8 +231,7 @@ void amdgpu_i2c_init(struct amdgpu_device *adev)
if (amdgpu_hw_i2c)
DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
- if (adev->is_atom_bios)
- amdgpu_atombios_i2c_init(adev);
+ amdgpu_atombios_i2c_init(adev);
}
/* remove all the buses */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index 216a9572d946..e02a70dd37b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -116,8 +116,8 @@ void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib,
* to SI there was just a DE IB.
*/
int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
- struct amdgpu_ib *ibs, struct dma_fence *last_vm_update,
- struct amdgpu_job *job, struct dma_fence **f)
+ struct amdgpu_ib *ibs, struct amdgpu_job *job,
+ struct dma_fence **f)
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_ib *ib = &ibs[0];
@@ -175,15 +175,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
if (ring->funcs->emit_hdp_flush)
amdgpu_ring_emit_hdp_flush(ring);
- /* always set cond_exec_polling to CONTINUE */
- *ring->cond_exe_cpu_addr = 1;
-
skip_preamble = ring->current_ctx == fence_ctx;
need_ctx_switch = ring->current_ctx != fence_ctx;
if (job && ring->funcs->emit_cntxcntl) {
if (need_ctx_switch)
status |= AMDGPU_HAVE_CTX_SWITCH;
status |= job->preamble_status;
+
+ if (vm)
+ status |= AMDGPU_VM_DOMAIN;
amdgpu_ring_emit_cntxcntl(ring, status);
}
@@ -193,7 +193,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
/* drop preamble IBs if we don't have a context switch */
if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
skip_preamble &&
- !(status & AMDGPU_PREAMBLE_IB_PRESENT_FIRST))
+ !(status & AMDGPU_PREAMBLE_IB_PRESENT_FIRST) &&
+ !amdgpu_sriov_vf(adev)) /* for SRIOV preemption, Preamble CE ib must be inserted anyway */
continue;
amdgpu_ring_emit_ib(ring, ib, job ? job->vm_id : 0,
@@ -223,7 +224,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
amdgpu_ring_patch_cond_exec(ring, patch_offset);
ring->current_ctx = fence_ctx;
- if (ring->funcs->emit_switch_buffer)
+ if (vm && ring->funcs->emit_switch_buffer)
amdgpu_ring_emit_switch_buffer(ring);
amdgpu_ring_commit(ring);
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index a0de6286c453..86a12424c162 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -170,8 +170,7 @@ static struct dma_fence *amdgpu_job_run(struct amd_sched_job *sched_job)
BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL));
trace_amdgpu_sched_run_job(job);
- r = amdgpu_ib_schedule(job->ring, job->num_ibs, job->ibs,
- job->sync.last_vm_update, job, &fence);
+ r = amdgpu_ib_schedule(job->ring, job->num_ibs, job->ibs, job, &fence);
if (r)
DRM_ERROR("Error scheduling IBs (%d)\n", r);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 8aef25828888..61d94c745672 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -60,6 +60,9 @@ void amdgpu_driver_unload_kms(struct drm_device *dev)
if (adev->rmmio == NULL)
goto done_free;
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_virt_request_full_gpu(adev, false);
+
if (amdgpu_device_is_px(dev)) {
pm_runtime_get_sync(dev->dev);
pm_runtime_forbid(dev->dev);
@@ -138,6 +141,9 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
pm_runtime_put_autosuspend(dev->dev);
}
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_virt_release_full_gpu(adev, true);
+
out:
if (r) {
/* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */
@@ -569,6 +575,27 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
return -EINVAL;
}
}
+ case AMDGPU_INFO_NUM_HANDLES: {
+ struct drm_amdgpu_info_num_handles handle;
+
+ switch (info->query_hw_ip.type) {
+ case AMDGPU_HW_IP_UVD:
+ /* Starting Polaris, we support unlimited UVD handles */
+ if (adev->asic_type < CHIP_POLARIS10) {
+ handle.uvd_max_handles = adev->uvd.max_handles;
+ handle.uvd_used_handles = amdgpu_uvd_used_handles(adev);
+
+ return copy_to_user(out, &handle,
+ min((size_t)size, sizeof(handle))) ? -EFAULT : 0;
+ } else {
+ return -ENODATA;
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->query);
return -EINVAL;
@@ -628,6 +655,12 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
goto out_suspend;
}
+ if (amdgpu_sriov_vf(adev)) {
+ r = amdgpu_map_static_csa(adev, &fpriv->vm);
+ if (r)
+ goto out_suspend;
+ }
+
mutex_init(&fpriv->bo_list_lock);
idr_init(&fpriv->bo_list_handles);
@@ -666,6 +699,14 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
amdgpu_uvd_free_handles(adev, file_priv);
amdgpu_vce_free_handles(adev, file_priv);
+ if (amdgpu_sriov_vf(adev)) {
+ /* TODO: how to handle reserve failure */
+ BUG_ON(amdgpu_bo_reserve(adev->virt.csa_obj, false));
+ amdgpu_vm_bo_rmv(adev, fpriv->vm.csa_bo_va);
+ fpriv->vm.csa_bo_va = NULL;
+ amdgpu_bo_unreserve(adev->virt.csa_obj);
+ }
+
amdgpu_vm_fini(adev, &fpriv->vm);
idr_for_each_entry(&fpriv->bo_list_handles, list, handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index b60346792bf8..c12497bd3889 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -595,6 +595,21 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags, uint32_t target);
+void amdgpu_crtc_cleanup_flip_ctx(struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo);
+int amdgpu_crtc_prepare_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags,
+ uint32_t target,
+ struct amdgpu_flip_work **work,
+ struct amdgpu_bo **new_abo);
+
+void amdgpu_crtc_submit_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct amdgpu_flip_work *work,
+ struct amdgpu_bo *new_abo);
+
extern const struct drm_mode_config_funcs amdgpu_mode_funcs;
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index bf79b73e1538..d1aa291b2638 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -363,11 +363,31 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
bo->flags = flags;
+#ifdef CONFIG_X86_32
+ /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
+ * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
+ */
+ bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
+ /* Don't try to enable write-combining when it can't work, or things
+ * may be slow
+ * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
+ */
+
+#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
+ thanks to write-combining
+
+ if (bo->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
+ DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
+ "better performance thanks to write-combining\n");
+ bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+#else
/* For architectures that don't support WC memory,
* mask out the WC flag from the BO
*/
if (!drm_arch_can_wc_memory())
bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+#endif
amdgpu_fill_placement_to_bo(bo, placement);
/* Kernel allocation are uninterruptible */
@@ -386,6 +406,11 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
if (unlikely(r != 0))
return r;
+ bo->tbo.priority = ilog2(bo->tbo.num_pages);
+ if (kernel)
+ bo->tbo.priority *= 2;
+ bo->tbo.priority = min(bo->tbo.priority, (unsigned)(TTM_MAX_BO_PRIORITY - 1));
+
if (flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) {
struct dma_fence *fence;
@@ -408,7 +433,8 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
return 0;
fail_unreserve:
- ww_mutex_unlock(&bo->tbo.resv->lock);
+ if (!resv)
+ ww_mutex_unlock(&bo->tbo.resv->lock);
amdgpu_bo_unref(&bo);
return r;
}
@@ -472,7 +498,16 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
return r;
if (amdgpu_need_backup(adev) && (flags & AMDGPU_GEM_CREATE_SHADOW)) {
+ if (!resv) {
+ r = ww_mutex_lock(&(*bo_ptr)->tbo.resv->lock, NULL);
+ WARN_ON(r != 0);
+ }
+
r = amdgpu_bo_create_shadow(adev, size, byte_align, (*bo_ptr));
+
+ if (!resv)
+ ww_mutex_unlock(&(*bo_ptr)->tbo.resv->lock);
+
if (r)
amdgpu_bo_unref(bo_ptr);
}
@@ -849,6 +884,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
}
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
+ bool evict,
struct ttm_mem_reg *new_mem)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
@@ -861,6 +897,10 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
abo = container_of(bo, struct amdgpu_bo, tbo);
amdgpu_vm_bo_invalidate(adev, abo);
+ /* remember the eviction */
+ if (evict)
+ atomic64_inc(&adev->num_evictions);
+
/* update statistics */
if (!new_mem)
return;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index 5cbf59ec0f68..15a723adca76 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -114,6 +114,15 @@ static inline u64 amdgpu_bo_mmap_offset(struct amdgpu_bo *bo)
return drm_vma_node_offset_addr(&bo->tbo.vma_node);
}
+/**
+ * amdgpu_bo_gpu_accessible - return whether the bo is currently in memory that
+ * is accessible to the GPU.
+ */
+static inline bool amdgpu_bo_gpu_accessible(struct amdgpu_bo *bo)
+{
+ return bo->tbo.mem.mem_type != TTM_PL_SYSTEM;
+}
+
int amdgpu_bo_create(struct amdgpu_device *adev,
unsigned long size, int byte_align,
bool kernel, u32 domain, u64 flags,
@@ -155,7 +164,8 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
size_t buffer_size, uint32_t *metadata_size,
uint64_t *flags);
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *new_mem);
+ bool evict,
+ struct ttm_mem_reg *new_mem);
int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
bool shared);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 723ae682bf25..a61882ddc804 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -34,6 +34,28 @@
static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
+static const struct cg_flag_name clocks[] = {
+ {AMD_CG_SUPPORT_GFX_MGCG, "Graphics Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_GFX_MGLS, "Graphics Medium Grain memory Light Sleep"},
+ {AMD_CG_SUPPORT_GFX_CGCG, "Graphics Coarse Grain Clock Gating"},
+ {AMD_CG_SUPPORT_GFX_CGLS, "Graphics Coarse Grain memory Light Sleep"},
+ {AMD_CG_SUPPORT_GFX_CGTS, "Graphics Coarse Grain Tree Shader Clock Gating"},
+ {AMD_CG_SUPPORT_GFX_CGTS_LS, "Graphics Coarse Grain Tree Shader Light Sleep"},
+ {AMD_CG_SUPPORT_GFX_CP_LS, "Graphics Command Processor Light Sleep"},
+ {AMD_CG_SUPPORT_GFX_RLC_LS, "Graphics Run List Controller Light Sleep"},
+ {AMD_CG_SUPPORT_MC_LS, "Memory Controller Light Sleep"},
+ {AMD_CG_SUPPORT_MC_MGCG, "Memory Controller Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_SDMA_LS, "System Direct Memory Access Light Sleep"},
+ {AMD_CG_SUPPORT_SDMA_MGCG, "System Direct Memory Access Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_BIF_LS, "Bus Interface Light Sleep"},
+ {AMD_CG_SUPPORT_UVD_MGCG, "Unified Video Decoder Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_VCE_MGCG, "Video Compression Engine Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_HDP_LS, "Host Data Path Light Sleep"},
+ {AMD_CG_SUPPORT_HDP_MGCG, "Host Data Path Medium Grain Clock Gating"},
+ {AMD_CG_SUPPORT_ROM_MGCG, "Rom Medium Grain Clock Gating"},
+ {0, NULL},
+};
+
void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
{
if (adev->pp_enabled)
@@ -112,28 +134,23 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
+ enum amd_dpm_forced_level level;
if ((adev->flags & AMD_IS_PX) &&
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
return snprintf(buf, PAGE_SIZE, "off\n");
- if (adev->pp_enabled) {
- enum amd_dpm_forced_level level;
-
- level = amdgpu_dpm_get_performance_level(adev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
- (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
- (level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
- (level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" : "unknown");
- } else {
- enum amdgpu_dpm_forced_level level;
-
- level = adev->pm.dpm.forced_level;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
- (level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
- }
+ level = amdgpu_dpm_get_performance_level(adev);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+ (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
+ (level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
+ (level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" :
+ (level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) ? "profile_standard" :
+ (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) ? "profile_min_sclk" :
+ (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) ? "profile_min_mclk" :
+ (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) ? "profile_peak" :
+ "unknown");
}
static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
@@ -143,7 +160,8 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
- enum amdgpu_dpm_forced_level level;
+ enum amd_dpm_forced_level level;
+ enum amd_dpm_forced_level current_level;
int ret = 0;
/* Can't force performance level when the card is off */
@@ -151,19 +169,34 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
return -EINVAL;
+ current_level = amdgpu_dpm_get_performance_level(adev);
+
if (strncmp("low", buf, strlen("low")) == 0) {
- level = AMDGPU_DPM_FORCED_LEVEL_LOW;
+ level = AMD_DPM_FORCED_LEVEL_LOW;
} else if (strncmp("high", buf, strlen("high")) == 0) {
- level = AMDGPU_DPM_FORCED_LEVEL_HIGH;
+ level = AMD_DPM_FORCED_LEVEL_HIGH;
} else if (strncmp("auto", buf, strlen("auto")) == 0) {
- level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ level = AMD_DPM_FORCED_LEVEL_AUTO;
} else if (strncmp("manual", buf, strlen("manual")) == 0) {
- level = AMDGPU_DPM_FORCED_LEVEL_MANUAL;
- } else {
+ level = AMD_DPM_FORCED_LEVEL_MANUAL;
+ } else if (strncmp("profile_exit", buf, strlen("profile_exit")) == 0) {
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_EXIT;
+ } else if (strncmp("profile_standard", buf, strlen("profile_standard")) == 0) {
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD;
+ } else if (strncmp("profile_min_sclk", buf, strlen("profile_min_sclk")) == 0) {
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK;
+ } else if (strncmp("profile_min_mclk", buf, strlen("profile_min_mclk")) == 0) {
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK;
+ } else if (strncmp("profile_peak", buf, strlen("profile_peak")) == 0) {
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
+ } else {
count = -EINVAL;
goto fail;
}
+ if (current_level == level)
+ return count;
+
if (adev->pp_enabled)
amdgpu_dpm_force_performance_level(adev, level);
else {
@@ -180,6 +213,7 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
adev->pm.dpm.forced_level = level;
mutex_unlock(&adev->pm.mutex);
}
+
fail:
return count;
}
@@ -1060,9 +1094,9 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
if (adev->pm.funcs->force_performance_level) {
if (adev->pm.dpm.thermal_active) {
- enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
+ enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
/* force low perf level for thermal */
- amdgpu_dpm_force_performance_level(adev, AMDGPU_DPM_FORCED_LEVEL_LOW);
+ amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
/* save the user's level */
adev->pm.dpm.forced_level = level;
} else {
@@ -1351,12 +1385,27 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
return 0;
}
+static void amdgpu_parse_cg_state(struct seq_file *m, u32 flags)
+{
+ int i;
+
+ for (i = 0; clocks[i].flag; i++)
+ seq_printf(m, "\t%s: %s\n", clocks[i].name,
+ (flags & clocks[i].flag) ? "On" : "Off");
+}
+
static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = dev->dev_private;
struct drm_device *ddev = adev->ddev;
+ u32 flags = 0;
+
+ amdgpu_get_clockgating_state(adev, &flags);
+ seq_printf(m, "Clock Gating Flags Mask: 0x%x\n", flags);
+ amdgpu_parse_cg_state(m, flags);
+ seq_printf(m, "\n");
if (!adev->pm.dpm_enabled) {
seq_printf(m, "dpm not enabled\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h
index 5fd7734f15ca..c19c4d138751 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h
@@ -24,6 +24,12 @@
#ifndef __AMDGPU_PM_H__
#define __AMDGPU_PM_H__
+struct cg_flag_name
+{
+ u32 flag;
+ const char *name;
+};
+
int amdgpu_pm_sysfs_init(struct amdgpu_device *adev);
void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev);
void amdgpu_pm_print_power_states(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
index fc592c2b0e16..8856eccc37fa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
@@ -34,97 +34,83 @@
#include "cik_dpm.h"
#include "vi_dpm.h"
-static int amdgpu_powerplay_init(struct amdgpu_device *adev)
+static int amdgpu_create_pp_handle(struct amdgpu_device *adev)
{
- int ret = 0;
+ struct amd_pp_init pp_init;
struct amd_powerplay *amd_pp;
+ int ret;
amd_pp = &(adev->powerplay);
-
- if (adev->pp_enabled) {
- struct amd_pp_init *pp_init;
-
- pp_init = kzalloc(sizeof(struct amd_pp_init), GFP_KERNEL);
-
- if (pp_init == NULL)
- return -ENOMEM;
-
- pp_init->chip_family = adev->family;
- pp_init->chip_id = adev->asic_type;
- pp_init->device = amdgpu_cgs_create_device(adev);
- ret = amd_powerplay_init(pp_init, amd_pp);
- kfree(pp_init);
- } else {
- amd_pp->pp_handle = (void *)adev;
-
- switch (adev->asic_type) {
-#ifdef CONFIG_DRM_AMDGPU_SI
- case CHIP_TAHITI:
- case CHIP_PITCAIRN:
- case CHIP_VERDE:
- case CHIP_OLAND:
- case CHIP_HAINAN:
- amd_pp->ip_funcs = &si_dpm_ip_funcs;
- break;
-#endif
-#ifdef CONFIG_DRM_AMDGPU_CIK
- case CHIP_BONAIRE:
- case CHIP_HAWAII:
- amd_pp->ip_funcs = &ci_dpm_ip_funcs;
- break;
- case CHIP_KABINI:
- case CHIP_MULLINS:
- case CHIP_KAVERI:
- amd_pp->ip_funcs = &kv_dpm_ip_funcs;
- break;
-#endif
- case CHIP_CARRIZO:
- case CHIP_STONEY:
- amd_pp->ip_funcs = &cz_dpm_ip_funcs;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- }
- return ret;
+ pp_init.chip_family = adev->family;
+ pp_init.chip_id = adev->asic_type;
+ pp_init.pm_en = amdgpu_dpm != 0 ? true : false;
+ pp_init.feature_mask = amdgpu_pp_feature_mask;
+ pp_init.device = amdgpu_cgs_create_device(adev);
+ ret = amd_powerplay_create(&pp_init, &(amd_pp->pp_handle));
+ if (ret)
+ return -EINVAL;
+ return 0;
}
static int amdgpu_pp_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ struct amd_powerplay *amd_pp;
int ret = 0;
+ amd_pp = &(adev->powerplay);
+ adev->pp_enabled = false;
+ amd_pp->pp_handle = (void *)adev;
+
switch (adev->asic_type) {
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_TONGA:
case CHIP_FIJI:
case CHIP_TOPAZ:
- adev->pp_enabled = true;
- break;
case CHIP_CARRIZO:
case CHIP_STONEY:
- adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true;
+ adev->pp_enabled = true;
+ if (amdgpu_create_pp_handle(adev))
+ return -EINVAL;
+ amd_pp->ip_funcs = &pp_ip_funcs;
+ amd_pp->pp_funcs = &pp_dpm_funcs;
break;
/* These chips don't have powerplay implemenations */
+#ifdef CONFIG_DRM_AMDGPU_SI
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ case CHIP_OLAND:
+ case CHIP_HAINAN:
+ amd_pp->ip_funcs = &si_dpm_ip_funcs;
+ break;
+#endif
+#ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_BONAIRE:
case CHIP_HAWAII:
+ amd_pp->ip_funcs = &ci_dpm_ip_funcs;
+ break;
case CHIP_KABINI:
case CHIP_MULLINS:
case CHIP_KAVERI:
+ amd_pp->ip_funcs = &kv_dpm_ip_funcs;
+ break;
+#endif
default:
- adev->pp_enabled = false;
+ ret = -EINVAL;
break;
}
- ret = amdgpu_powerplay_init(adev);
- if (ret)
- return ret;
-
if (adev->powerplay.ip_funcs->early_init)
ret = adev->powerplay.ip_funcs->early_init(
adev->powerplay.pp_handle);
+
+ if (ret == PP_DPM_DISABLED) {
+ adev->pm.dpm_enabled = false;
+ return 0;
+ }
return ret;
}
@@ -184,6 +170,11 @@ static int amdgpu_pp_hw_init(void *handle)
ret = adev->powerplay.ip_funcs->hw_init(
adev->powerplay.pp_handle);
+ if (ret == PP_DPM_DISABLED) {
+ adev->pm.dpm_enabled = false;
+ return 0;
+ }
+
if ((amdgpu_dpm != 0) && !amdgpu_sriov_vf(adev))
adev->pm.dpm_enabled = true;
@@ -209,14 +200,14 @@ static void amdgpu_pp_late_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (adev->pp_enabled) {
- amdgpu_pm_sysfs_fini(adev);
- amd_powerplay_fini(adev->powerplay.pp_handle);
- }
-
if (adev->powerplay.ip_funcs->late_fini)
adev->powerplay.ip_funcs->late_fini(
adev->powerplay.pp_handle);
+
+ if (adev->pp_enabled && adev->pm.dpm_enabled)
+ amdgpu_pm_sysfs_fini(adev);
+
+ amd_powerplay_destroy(adev->powerplay.pp_handle);
}
static int amdgpu_pp_suspend(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index a47628395914..7c842b7f1004 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -207,6 +207,8 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
}
ring->cond_exe_gpu_addr = adev->wb.gpu_addr + (ring->cond_exe_offs * 4);
ring->cond_exe_cpu_addr = &adev->wb.wb[ring->cond_exe_offs];
+ /* always set cond_exec_polling to CONTINUE */
+ *ring->cond_exe_cpu_addr = 1;
r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type);
if (r) {
@@ -307,7 +309,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
while (size) {
if (*pos >= (ring->ring_size + 12))
return result;
-
+
value = ring->ring[(*pos - 12)/4];
r = put_user(value, (uint32_t*)buf);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index 574f0b79c690..2345b39878c6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -135,6 +135,8 @@ struct amdgpu_ring_funcs {
void (*end_use)(struct amdgpu_ring *ring);
void (*emit_switch_buffer) (struct amdgpu_ring *ring);
void (*emit_cntxcntl) (struct amdgpu_ring *ring, uint32_t flags);
+ void (*emit_rreg)(struct amdgpu_ring *ring, uint32_t reg);
+ void (*emit_wreg)(struct amdgpu_ring *ring, uint32_t reg, uint32_t val);
};
struct amdgpu_ring {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index bb964a8ff938..a18ae1e97860 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -24,7 +24,7 @@ TRACE_EVENT(amdgpu_mm_rreg,
__entry->reg = reg;
__entry->value = value;
),
- TP_printk("0x%04lx, 0x%04lx, 0x%08lx",
+ TP_printk("0x%04lx, 0x%08lx, 0x%08lx",
(unsigned long)__entry->did,
(unsigned long)__entry->reg,
(unsigned long)__entry->value)
@@ -43,7 +43,7 @@ TRACE_EVENT(amdgpu_mm_wreg,
__entry->reg = reg;
__entry->value = value;
),
- TP_printk("0x%04lx, 0x%04lx, 0x%08lx",
+ TP_printk("0x%04lx, 0x%08lx, 0x%08lx",
(unsigned long)__entry->did,
(unsigned long)__entry->reg,
(unsigned long)__entry->value)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index c695b6c55361..1154b0a8881d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -466,10 +466,6 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo,
adev = amdgpu_ttm_adev(bo->bdev);
- /* remember the eviction */
- if (evict)
- atomic64_inc(&adev->num_evictions);
-
if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
amdgpu_move_null(bo, new_mem);
return 0;
@@ -552,6 +548,8 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
mem->bus.addr =
ioremap_nocache(mem->bus.base + mem->bus.offset,
mem->bus.size);
+ if (!mem->bus.addr)
+ return -ENOMEM;
/*
* Alpha: Use just the bus offset plus
@@ -1052,56 +1050,6 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
return flags;
}
-static void amdgpu_ttm_lru_removal(struct ttm_buffer_object *tbo)
-{
- struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
- unsigned i, j;
-
- for (i = 0; i < AMDGPU_TTM_LRU_SIZE; ++i) {
- struct amdgpu_mman_lru *lru = &adev->mman.log2_size[i];
-
- for (j = 0; j < TTM_NUM_MEM_TYPES; ++j)
- if (&tbo->lru == lru->lru[j])
- lru->lru[j] = tbo->lru.prev;
-
- if (&tbo->swap == lru->swap_lru)
- lru->swap_lru = tbo->swap.prev;
- }
-}
-
-static struct amdgpu_mman_lru *amdgpu_ttm_lru(struct ttm_buffer_object *tbo)
-{
- struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
- unsigned log2_size = min(ilog2(tbo->num_pages),
- AMDGPU_TTM_LRU_SIZE - 1);
-
- return &adev->mman.log2_size[log2_size];
-}
-
-static struct list_head *amdgpu_ttm_lru_tail(struct ttm_buffer_object *tbo)
-{
- struct amdgpu_mman_lru *lru = amdgpu_ttm_lru(tbo);
- struct list_head *res = lru->lru[tbo->mem.mem_type];
-
- lru->lru[tbo->mem.mem_type] = &tbo->lru;
- while ((++lru)->lru[tbo->mem.mem_type] == res)
- lru->lru[tbo->mem.mem_type] = &tbo->lru;
-
- return res;
-}
-
-static struct list_head *amdgpu_ttm_swap_lru_tail(struct ttm_buffer_object *tbo)
-{
- struct amdgpu_mman_lru *lru = amdgpu_ttm_lru(tbo);
- struct list_head *res = lru->swap_lru;
-
- lru->swap_lru = &tbo->swap;
- while ((++lru)->swap_lru == res)
- lru->swap_lru = &tbo->swap;
-
- return res;
-}
-
static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
const struct ttm_place *place)
{
@@ -1140,14 +1088,10 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
.fault_reserve_notify = &amdgpu_bo_fault_reserve_notify,
.io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
.io_mem_free = &amdgpu_ttm_io_mem_free,
- .lru_removal = &amdgpu_ttm_lru_removal,
- .lru_tail = &amdgpu_ttm_lru_tail,
- .swap_lru_tail = &amdgpu_ttm_swap_lru_tail,
};
int amdgpu_ttm_init(struct amdgpu_device *adev)
{
- unsigned i, j;
int r;
r = amdgpu_ttm_global_init(adev);
@@ -1165,19 +1109,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
return r;
}
-
- for (i = 0; i < AMDGPU_TTM_LRU_SIZE; ++i) {
- struct amdgpu_mman_lru *lru = &adev->mman.log2_size[i];
-
- for (j = 0; j < TTM_NUM_MEM_TYPES; ++j)
- lru->lru[j] = &adev->mman.bdev.man[j].lru;
- lru->swap_lru = &adev->mman.bdev.glob->swap_lru;
- }
-
- for (j = 0; j < TTM_NUM_MEM_TYPES; ++j)
- adev->mman.guard.lru[j] = NULL;
- adev->mman.guard.swap_lru = NULL;
-
adev->mman.initialized = true;
r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM,
adev->mc.real_vram_size >> PAGE_SHIFT);
@@ -1365,7 +1296,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring,
WARN_ON(job->ibs[0].length_dw > num_dw);
if (direct_submit) {
r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs,
- NULL, NULL, fence);
+ NULL, fence);
job->fence = dma_fence_get(*fence);
if (r)
DRM_ERROR("Error scheduling IBs (%d)\n", r);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index 98ee384f0fca..6bdede8ff12b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -34,13 +34,6 @@
#define AMDGPU_PL_FLAG_GWS (TTM_PL_FLAG_PRIV << 1)
#define AMDGPU_PL_FLAG_OA (TTM_PL_FLAG_PRIV << 2)
-#define AMDGPU_TTM_LRU_SIZE 20
-
-struct amdgpu_mman_lru {
- struct list_head *lru[TTM_NUM_MEM_TYPES];
- struct list_head *swap_lru;
-};
-
struct amdgpu_mman {
struct ttm_bo_global_ref bo_global_ref;
struct drm_global_reference mem_global_ref;
@@ -58,11 +51,6 @@ struct amdgpu_mman {
struct amdgpu_ring *buffer_funcs_ring;
/* Scheduler entity for buffer moves */
struct amd_sched_entity entity;
-
- /* custom LRU management */
- struct amdgpu_mman_lru log2_size[AMDGPU_TTM_LRU_SIZE];
- /* guard for log2_size array, don't add anything in between */
- struct amdgpu_mman_lru guard;
};
extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index a81dfaeeb8c0..6f62ac473064 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -65,6 +65,7 @@
#define FIRMWARE_STONEY "amdgpu/stoney_uvd.bin"
#define FIRMWARE_POLARIS10 "amdgpu/polaris10_uvd.bin"
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin"
+#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin"
/**
* amdgpu_uvd_cs_ctx - Command submission parser context
@@ -98,6 +99,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI);
MODULE_FIRMWARE(FIRMWARE_STONEY);
MODULE_FIRMWARE(FIRMWARE_POLARIS10);
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
@@ -149,6 +151,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
case CHIP_POLARIS11:
fw_name = FIRMWARE_POLARIS11;
break;
+ case CHIP_POLARIS12:
+ fw_name = FIRMWARE_POLARIS12;
+ break;
default:
return -EINVAL;
}
@@ -971,7 +976,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
ib->length_dw = 16;
if (direct) {
- r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
job->fence = dma_fence_get(f);
if (r)
goto err_free;
@@ -1173,3 +1178,28 @@ int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout)
error:
return r;
}
+
+/**
+ * amdgpu_uvd_used_handles - returns used UVD handles
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Returns the number of UVD handles in use
+ */
+uint32_t amdgpu_uvd_used_handles(struct amdgpu_device *adev)
+{
+ unsigned i;
+ uint32_t used_handles = 0;
+
+ for (i = 0; i < adev->uvd.max_handles; ++i) {
+ /*
+ * Handles can be freed in any order, and not
+ * necessarily linear. So we need to count
+ * all non-zero handles.
+ */
+ if (atomic_read(&adev->uvd.handles[i]))
+ used_handles++;
+ }
+
+ return used_handles;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
index 6249ba1bde2a..c10682baccae 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
@@ -38,5 +38,6 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx);
void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring);
void amdgpu_uvd_ring_end_use(struct amdgpu_ring *ring);
int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout);
+uint32_t amdgpu_uvd_used_handles(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 69b66b9e7f57..79bc9c7aad45 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -52,6 +52,7 @@
#define FIRMWARE_STONEY "amdgpu/stoney_vce.bin"
#define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin"
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin"
+#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin"
#ifdef CONFIG_DRM_AMDGPU_CIK
MODULE_FIRMWARE(FIRMWARE_BONAIRE);
@@ -66,6 +67,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI);
MODULE_FIRMWARE(FIRMWARE_STONEY);
MODULE_FIRMWARE(FIRMWARE_POLARIS10);
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
static void amdgpu_vce_idle_work_handler(struct work_struct *work);
@@ -121,6 +123,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
case CHIP_POLARIS11:
fw_name = FIRMWARE_POLARIS11;
break;
+ case CHIP_POLARIS12:
+ fw_name = FIRMWARE_POLARIS12;
+ break;
default:
return -EINVAL;
@@ -450,7 +455,7 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
for (i = ib->length_dw; i < ib_size_dw; ++i)
ib->ptr[i] = 0x0;
- r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
job->fence = dma_fence_get(f);
if (r)
goto err;
@@ -513,7 +518,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
ib->ptr[i] = 0x0;
if (direct) {
- r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
job->fence = dma_fence_get(f);
if (r)
goto err;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
new file mode 100644
index 000000000000..3fd951c71d1b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "amdgpu.h"
+
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev)
+{
+ int r;
+ void *ptr;
+
+ r = amdgpu_bo_create_kernel(adev, AMDGPU_CSA_SIZE, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM, &adev->virt.csa_obj,
+ &adev->virt.csa_vmid0_addr, &ptr);
+ if (r)
+ return r;
+
+ memset(ptr, 0, AMDGPU_CSA_SIZE);
+ return 0;
+}
+
+/*
+ * amdgpu_map_static_csa should be called during amdgpu_vm_init
+ * it maps virtual address "AMDGPU_VA_RESERVED_SIZE - AMDGPU_CSA_SIZE"
+ * to this VM, and each command submission of GFX should use this virtual
+ * address within META_DATA init package to support SRIOV gfx preemption.
+ */
+
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+{
+ int r;
+ struct amdgpu_bo_va *bo_va;
+ struct ww_acquire_ctx ticket;
+ struct list_head list;
+ struct amdgpu_bo_list_entry pd;
+ struct ttm_validate_buffer csa_tv;
+
+ INIT_LIST_HEAD(&list);
+ INIT_LIST_HEAD(&csa_tv.head);
+ csa_tv.bo = &adev->virt.csa_obj->tbo;
+ csa_tv.shared = true;
+
+ list_add(&csa_tv.head, &list);
+ amdgpu_vm_get_pd_bo(vm, &list, &pd);
+
+ r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
+ if (r) {
+ DRM_ERROR("failed to reserve CSA,PD BOs: err=%d\n", r);
+ return r;
+ }
+
+ bo_va = amdgpu_vm_bo_add(adev, vm, adev->virt.csa_obj);
+ if (!bo_va) {
+ ttm_eu_backoff_reservation(&ticket, &list);
+ DRM_ERROR("failed to create bo_va for static CSA\n");
+ return -ENOMEM;
+ }
+
+ r = amdgpu_vm_bo_map(adev, bo_va, AMDGPU_CSA_VADDR, 0,AMDGPU_CSA_SIZE,
+ AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
+ AMDGPU_PTE_EXECUTABLE);
+
+ if (r) {
+ DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
+ amdgpu_vm_bo_rmv(adev, bo_va);
+ ttm_eu_backoff_reservation(&ticket, &list);
+ kfree(bo_va);
+ return r;
+ }
+
+ vm->csa_bo_va = bo_va;
+ ttm_eu_backoff_reservation(&ticket, &list);
+ return 0;
+}
+
+void amdgpu_virt_init_setting(struct amdgpu_device *adev)
+{
+ /* enable virtual display */
+ adev->mode_info.num_crtc = 1;
+ adev->enable_virtual_display = true;
+
+ mutex_init(&adev->virt.lock);
+}
+
+uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
+{
+ signed long r;
+ uint32_t val;
+ struct dma_fence *f;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *ring = &kiq->ring;
+
+ BUG_ON(!ring->funcs->emit_rreg);
+
+ mutex_lock(&adev->virt.lock);
+ amdgpu_ring_alloc(ring, 32);
+ amdgpu_ring_emit_hdp_flush(ring);
+ amdgpu_ring_emit_rreg(ring, reg);
+ amdgpu_ring_emit_hdp_invalidate(ring);
+ amdgpu_fence_emit(ring, &f);
+ amdgpu_ring_commit(ring);
+ mutex_unlock(&adev->virt.lock);
+
+ r = dma_fence_wait(f, false);
+ if (r)
+ DRM_ERROR("wait for kiq fence error: %ld.\n", r);
+ dma_fence_put(f);
+
+ val = adev->wb.wb[adev->virt.reg_val_offs];
+
+ return val;
+}
+
+void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
+{
+ signed long r;
+ struct dma_fence *f;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *ring = &kiq->ring;
+
+ BUG_ON(!ring->funcs->emit_wreg);
+
+ mutex_lock(&adev->virt.lock);
+ amdgpu_ring_alloc(ring, 32);
+ amdgpu_ring_emit_hdp_flush(ring);
+ amdgpu_ring_emit_wreg(ring, reg, v);
+ amdgpu_ring_emit_hdp_invalidate(ring);
+ amdgpu_fence_emit(ring, &f);
+ amdgpu_ring_commit(ring);
+ mutex_unlock(&adev->virt.lock);
+
+ r = dma_fence_wait(f, false);
+ if (r)
+ DRM_ERROR("wait for kiq fence error: %ld.\n", r);
+ dma_fence_put(f);
+}
+
+/**
+ * amdgpu_virt_request_full_gpu() - request full gpu access
+ * @amdgpu: amdgpu device.
+ * @init: is driver init time.
+ * When start to init/fini driver, first need to request full gpu access.
+ * Return: Zero if request success, otherwise will return error.
+ */
+int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init)
+{
+ struct amdgpu_virt *virt = &adev->virt;
+ int r;
+
+ if (virt->ops && virt->ops->req_full_gpu) {
+ r = virt->ops->req_full_gpu(adev, init);
+ if (r)
+ return r;
+
+ adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_virt_release_full_gpu() - release full gpu access
+ * @amdgpu: amdgpu device.
+ * @init: is driver init time.
+ * When finishing driver init/fini, need to release full gpu access.
+ * Return: Zero if release success, otherwise will returen error.
+ */
+int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init)
+{
+ struct amdgpu_virt *virt = &adev->virt;
+ int r;
+
+ if (virt->ops && virt->ops->rel_full_gpu) {
+ r = virt->ops->rel_full_gpu(adev, init);
+ if (r)
+ return r;
+
+ adev->virt.caps |= AMDGPU_SRIOV_CAPS_RUNTIME;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_virt_reset_gpu() - reset gpu
+ * @amdgpu: amdgpu device.
+ * Send reset command to GPU hypervisor to reset GPU that VM is using
+ * Return: Zero if reset success, otherwise will return error.
+ */
+int amdgpu_virt_reset_gpu(struct amdgpu_device *adev)
+{
+ struct amdgpu_virt *virt = &adev->virt;
+ int r;
+
+ if (virt->ops && virt->ops->reset_gpu) {
+ r = virt->ops->reset_gpu(adev);
+ if (r)
+ return r;
+
+ adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
index 2c37a374917f..675e12c42532 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -28,22 +28,48 @@
#define AMDGPU_SRIOV_CAPS_ENABLE_IOV (1 << 1) /* sr-iov is enabled on this GPU */
#define AMDGPU_SRIOV_CAPS_IS_VF (1 << 2) /* this GPU is a virtual function */
#define AMDGPU_PASSTHROUGH_MODE (1 << 3) /* thw whole GPU is pass through for VM */
+#define AMDGPU_SRIOV_CAPS_RUNTIME (1 << 4) /* is out of full access mode */
+
+/**
+ * struct amdgpu_virt_ops - amdgpu device virt operations
+ */
+struct amdgpu_virt_ops {
+ int (*req_full_gpu)(struct amdgpu_device *adev, bool init);
+ int (*rel_full_gpu)(struct amdgpu_device *adev, bool init);
+ int (*reset_gpu)(struct amdgpu_device *adev);
+};
+
/* GPU virtualization */
-struct amdgpu_virtualization {
- uint32_t virtual_caps;
+struct amdgpu_virt {
+ uint32_t caps;
+ struct amdgpu_bo *csa_obj;
+ uint64_t csa_vmid0_addr;
+ bool chained_ib_support;
+ uint32_t reg_val_offs;
+ struct mutex lock;
+ struct amdgpu_irq_src ack_irq;
+ struct amdgpu_irq_src rcv_irq;
+ struct delayed_work flr_work;
+ const struct amdgpu_virt_ops *ops;
};
+#define AMDGPU_CSA_SIZE (8 * 1024)
+#define AMDGPU_CSA_VADDR (AMDGPU_VA_RESERVED_SIZE - AMDGPU_CSA_SIZE)
+
#define amdgpu_sriov_enabled(adev) \
-((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
+((adev)->virt.caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
#define amdgpu_sriov_vf(adev) \
-((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_IS_VF)
+((adev)->virt.caps & AMDGPU_SRIOV_CAPS_IS_VF)
#define amdgpu_sriov_bios(adev) \
-((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS)
+((adev)->virt.caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS)
+
+#define amdgpu_sriov_runtime(adev) \
+((adev)->virt.caps & AMDGPU_SRIOV_CAPS_RUNTIME)
#define amdgpu_passthrough(adev) \
-((adev)->virtualization.virtual_caps & AMDGPU_PASSTHROUGH_MODE)
+((adev)->virt.caps & AMDGPU_PASSTHROUGH_MODE)
static inline bool is_virtual_machine(void)
{
@@ -54,4 +80,14 @@ static inline bool is_virtual_machine(void)
#endif
}
-#endif \ No newline at end of file
+struct amdgpu_vm;
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev);
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+void amdgpu_virt_init_setting(struct amdgpu_device *adev);
+uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg);
+void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v);
+int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init);
+int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init);
+int amdgpu_virt_reset_gpu(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 1dda9321bd5a..bd0d33125c18 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1293,7 +1293,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
int amdgpu_vm_bo_map(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
uint64_t saddr, uint64_t offset,
- uint64_t size, uint32_t flags)
+ uint64_t size, uint64_t flags)
{
struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_vm *vm = bo_va->vm;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index adbc2f5e5c7f..18c72c0b478d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -111,6 +111,8 @@ struct amdgpu_vm {
/* client id */
u64 client_id;
+ /* each VM will map on CSA */
+ struct amdgpu_bo_va *csa_bo_va;
};
struct amdgpu_vm_id {
@@ -195,7 +197,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
int amdgpu_vm_bo_map(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
uint64_t addr, uint64_t offset,
- uint64_t size, uint32_t flags);
+ uint64_t size, uint64_t flags);
int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
uint64_t addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
index c32eca26155c..2af26d2da127 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -181,9 +181,6 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode
if (!amdgpu_encoder->enc_priv)
return;
- if (!adev->is_atom_bios)
- return;
-
if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
return;
@@ -236,9 +233,6 @@ amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *amdgpu_encoder)
if (!amdgpu_encoder->enc_priv)
return;
- if (!adev->is_atom_bios)
- return;
-
if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
return;
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index bda9e3de191e..9498e78b90d7 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -889,7 +889,16 @@ static void ci_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
pi->uvd_power_gated = gate;
- ci_update_uvd_dpm(adev, gate);
+ if (gate) {
+ /* stop the UVD block */
+ amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+ ci_update_uvd_dpm(adev, gate);
+ } else {
+ amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_UNGATE);
+ ci_update_uvd_dpm(adev, gate);
+ }
}
static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev)
@@ -4336,13 +4345,13 @@ static u32 ci_get_lowest_enabled_level(struct amdgpu_device *adev,
static int ci_dpm_force_performance_level(struct amdgpu_device *adev,
- enum amdgpu_dpm_forced_level level)
+ enum amd_dpm_forced_level level)
{
struct ci_power_info *pi = ci_get_pi(adev);
u32 tmp, levels, i;
int ret;
- if (level == AMDGPU_DPM_FORCED_LEVEL_HIGH) {
+ if (level == AMD_DPM_FORCED_LEVEL_HIGH) {
if ((!pi->pcie_dpm_key_disabled) &&
pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
levels = 0;
@@ -4403,7 +4412,7 @@ static int ci_dpm_force_performance_level(struct amdgpu_device *adev,
}
}
}
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_LOW) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_LOW) {
if ((!pi->sclk_dpm_key_disabled) &&
pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
levels = ci_get_lowest_enabled_level(adev,
@@ -4452,7 +4461,7 @@ static int ci_dpm_force_performance_level(struct amdgpu_device *adev,
udelay(1);
}
}
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_AUTO) {
if (!pi->pcie_dpm_key_disabled) {
PPSMC_Result smc_result;
@@ -6262,7 +6271,7 @@ static int ci_dpm_sw_init(void *handle)
/* default to balanced state */
adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ adev->pm.dpm.forced_level = AMD_DPM_FORCED_LEVEL_AUTO;
adev->pm.default_sclk = adev->clock.default_sclk;
adev->pm.default_mclk = adev->clock.default_mclk;
adev->pm.current_sclk = adev->clock.default_sclk;
@@ -6571,8 +6580,9 @@ static int ci_dpm_force_clock_level(struct amdgpu_device *adev,
{
struct ci_power_info *pi = ci_get_pi(adev);
- if (adev->pm.dpm.forced_level
- != AMDGPU_DPM_FORCED_LEVEL_MANUAL)
+ if (adev->pm.dpm.forced_level & (AMD_DPM_FORCED_LEVEL_AUTO |
+ AMD_DPM_FORCED_LEVEL_LOW |
+ AMD_DPM_FORCED_LEVEL_HIGH))
return -EINVAL;
switch (type) {
@@ -6739,12 +6749,3 @@ static void ci_dpm_set_irq_funcs(struct amdgpu_device *adev)
adev->pm.dpm.thermal.irq.num_types = AMDGPU_THERMAL_IRQ_LAST;
adev->pm.dpm.thermal.irq.funcs = &ci_dpm_irq_funcs;
}
-
-const struct amdgpu_ip_block_version ci_dpm_ip_block =
-{
- .type = AMD_IP_BLOCK_TYPE_SMC,
- .major = 7,
- .minor = 0,
- .rev = 0,
- .funcs = &ci_dpm_ip_funcs,
-};
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
index 302df85893ab..7da688b0d27d 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -1627,14 +1627,13 @@ static uint32_t cik_get_rev_id(struct amdgpu_device *adev)
static void cik_detect_hw_virtualization(struct amdgpu_device *adev)
{
if (is_virtual_machine()) /* passthrough mode */
- adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
+ adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE;
}
static const struct amdgpu_asic_funcs cik_asic_funcs =
{
.read_disabled_bios = &cik_read_disabled_bios,
.read_bios_from_rom = &cik_read_bios_from_rom,
- .detect_hw_virtualization = cik_detect_hw_virtualization,
.read_register = &cik_read_register,
.reset = &cik_asic_reset,
.set_vga_state = &cik_vga_set_state,
@@ -1890,6 +1889,8 @@ static const struct amdgpu_ip_block_version cik_common_ip_block =
int cik_set_ip_blocks(struct amdgpu_device *adev)
{
+ cik_detect_hw_virtualization(adev);
+
switch (adev->asic_type) {
case CHIP_BONAIRE:
amdgpu_ip_block_add(adev, &cik_common_ip_block);
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index 4c34dbc7a254..810bba533975 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -651,7 +651,7 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[3] = 1;
ib.ptr[4] = 0xDEADBEEF;
ib.length_dw = 5;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err1;
diff --git a/drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h b/drivers/gpu/drm/amd/amdgpu/clearstate_si.h
index 66e39cdb5cb0..66e39cdb5cb0 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h
+++ b/drivers/gpu/drm/amd/amdgpu/clearstate_si.h
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
deleted file mode 100644
index ba2b66be9022..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
+++ /dev/null
@@ -1,2320 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <linux/firmware.h>
-#include <linux/seq_file.h>
-#include "drmP.h"
-#include "amdgpu.h"
-#include "amdgpu_pm.h"
-#include "amdgpu_atombios.h"
-#include "vid.h"
-#include "vi_dpm.h"
-#include "amdgpu_dpm.h"
-#include "cz_dpm.h"
-#include "cz_ppsmc.h"
-#include "atom.h"
-
-#include "smu/smu_8_0_d.h"
-#include "smu/smu_8_0_sh_mask.h"
-#include "gca/gfx_8_0_d.h"
-#include "gca/gfx_8_0_sh_mask.h"
-#include "gmc/gmc_8_1_d.h"
-#include "bif/bif_5_1_d.h"
-#include "gfx_v8_0.h"
-
-static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate);
-static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate);
-static void cz_dpm_fini(struct amdgpu_device *adev);
-
-static struct cz_ps *cz_get_ps(struct amdgpu_ps *rps)
-{
- struct cz_ps *ps = rps->ps_priv;
-
- return ps;
-}
-
-static struct cz_power_info *cz_get_pi(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = adev->pm.dpm.priv;
-
- return pi;
-}
-
-static uint16_t cz_convert_8bit_index_to_voltage(struct amdgpu_device *adev,
- uint16_t voltage)
-{
- uint16_t tmp = 6200 - voltage * 25;
-
- return tmp;
-}
-
-static void cz_construct_max_power_limits_table(struct amdgpu_device *adev,
- struct amdgpu_clock_and_voltage_limits *table)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *dep_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
-
- if (dep_table->count > 0) {
- table->sclk = dep_table->entries[dep_table->count - 1].clk;
- table->vddc = cz_convert_8bit_index_to_voltage(adev,
- dep_table->entries[dep_table->count - 1].v);
- }
-
- table->mclk = pi->sys_info.nbp_memory_clock[0];
-
-}
-
-union igp_info {
- struct _ATOM_INTEGRATED_SYSTEM_INFO info;
- struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
- struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
- struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;
-};
-
-static int cz_parse_sys_info_table(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_mode_info *mode_info = &adev->mode_info;
- int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
- union igp_info *igp_info;
- u8 frev, crev;
- u16 data_offset;
- int i = 0;
-
- if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
- &frev, &crev, &data_offset)) {
- igp_info = (union igp_info *)(mode_info->atom_context->bios +
- data_offset);
-
- if (crev != 9) {
- DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
- return -EINVAL;
- }
- pi->sys_info.bootup_sclk =
- le32_to_cpu(igp_info->info_9.ulBootUpEngineClock);
- pi->sys_info.bootup_uma_clk =
- le32_to_cpu(igp_info->info_9.ulBootUpUMAClock);
- pi->sys_info.dentist_vco_freq =
- le32_to_cpu(igp_info->info_9.ulDentistVCOFreq);
- pi->sys_info.bootup_nb_voltage_index =
- le16_to_cpu(igp_info->info_9.usBootUpNBVoltage);
-
- if (igp_info->info_9.ucHtcTmpLmt == 0)
- pi->sys_info.htc_tmp_lmt = 203;
- else
- pi->sys_info.htc_tmp_lmt = igp_info->info_9.ucHtcTmpLmt;
-
- if (igp_info->info_9.ucHtcHystLmt == 0)
- pi->sys_info.htc_hyst_lmt = 5;
- else
- pi->sys_info.htc_hyst_lmt = igp_info->info_9.ucHtcHystLmt;
-
- if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
- DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
- return -EINVAL;
- }
-
- if (le32_to_cpu(igp_info->info_9.ulSystemConfig) & (1 << 3) &&
- pi->enable_nb_ps_policy)
- pi->sys_info.nb_dpm_enable = true;
- else
- pi->sys_info.nb_dpm_enable = false;
-
- for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
- if (i < CZ_NUM_NBPMEMORY_CLOCK)
- pi->sys_info.nbp_memory_clock[i] =
- le32_to_cpu(igp_info->info_9.ulNbpStateMemclkFreq[i]);
- pi->sys_info.nbp_n_clock[i] =
- le32_to_cpu(igp_info->info_9.ulNbpStateNClkFreq[i]);
- }
-
- for (i = 0; i < CZ_MAX_DISPLAY_CLOCK_LEVEL; i++)
- pi->sys_info.display_clock[i] =
- le32_to_cpu(igp_info->info_9.sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
-
- for (i = 0; i < CZ_NUM_NBPSTATES; i++)
- pi->sys_info.nbp_voltage_index[i] =
- le32_to_cpu(igp_info->info_9.usNBPStateVoltage[i]);
-
- if (le32_to_cpu(igp_info->info_9.ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
- pi->caps_enable_dfs_bypass = true;
-
- pi->sys_info.uma_channel_number =
- igp_info->info_9.ucUMAChannelNumber;
-
- cz_construct_max_power_limits_table(adev,
- &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
- }
-
- return 0;
-}
-
-static void cz_patch_voltage_values(struct amdgpu_device *adev)
-{
- int i;
- struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
- struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
- struct amdgpu_clock_voltage_dependency_table *acp_table =
- &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
-
- if (uvd_table->count) {
- for (i = 0; i < uvd_table->count; i++)
- uvd_table->entries[i].v =
- cz_convert_8bit_index_to_voltage(adev,
- uvd_table->entries[i].v);
- }
-
- if (vce_table->count) {
- for (i = 0; i < vce_table->count; i++)
- vce_table->entries[i].v =
- cz_convert_8bit_index_to_voltage(adev,
- vce_table->entries[i].v);
- }
-
- if (acp_table->count) {
- for (i = 0; i < acp_table->count; i++)
- acp_table->entries[i].v =
- cz_convert_8bit_index_to_voltage(adev,
- acp_table->entries[i].v);
- }
-
-}
-
-static void cz_construct_boot_state(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
- pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
- pi->boot_pl.ds_divider_index = 0;
- pi->boot_pl.ss_divider_index = 0;
- pi->boot_pl.allow_gnb_slow = 1;
- pi->boot_pl.force_nbp_state = 0;
- pi->boot_pl.display_wm = 0;
- pi->boot_pl.vce_wm = 0;
-
-}
-
-static void cz_patch_boot_state(struct amdgpu_device *adev,
- struct cz_ps *ps)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- ps->num_levels = 1;
- ps->levels[0] = pi->boot_pl;
-}
-
-union pplib_clock_info {
- struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
- struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
- struct _ATOM_PPLIB_CZ_CLOCK_INFO carrizo;
-};
-
-static void cz_parse_pplib_clock_info(struct amdgpu_device *adev,
- struct amdgpu_ps *rps, int index,
- union pplib_clock_info *clock_info)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct cz_ps *ps = cz_get_ps(rps);
- struct cz_pl *pl = &ps->levels[index];
- struct amdgpu_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
-
- pl->sclk = table->entries[clock_info->carrizo.index].clk;
- pl->vddc_index = table->entries[clock_info->carrizo.index].v;
-
- ps->num_levels = index + 1;
-
- if (pi->caps_sclk_ds) {
- pl->ds_divider_index = 5;
- pl->ss_divider_index = 5;
- }
-
-}
-
-static void cz_parse_pplib_non_clock_info(struct amdgpu_device *adev,
- struct amdgpu_ps *rps,
- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
- u8 table_rev)
-{
- struct cz_ps *ps = cz_get_ps(rps);
-
- rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
- rps->class = le16_to_cpu(non_clock_info->usClassification);
- rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
-
- if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
- rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
- rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
- } else {
- rps->vclk = 0;
- rps->dclk = 0;
- }
-
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
- adev->pm.dpm.boot_ps = rps;
- cz_patch_boot_state(adev, ps);
- }
- if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
- adev->pm.dpm.uvd_ps = rps;
-
-}
-
-union power_info {
- struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
- struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
- struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
- struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
- struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
-};
-
-union pplib_power_state {
- struct _ATOM_PPLIB_STATE v1;
- struct _ATOM_PPLIB_STATE_V2 v2;
-};
-
-static int cz_parse_power_table(struct amdgpu_device *adev)
-{
- struct amdgpu_mode_info *mode_info = &adev->mode_info;
- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
- union pplib_power_state *power_state;
- int i, j, k, non_clock_array_index, clock_array_index;
- union pplib_clock_info *clock_info;
- struct _StateArray *state_array;
- struct _ClockInfoArray *clock_info_array;
- struct _NonClockInfoArray *non_clock_info_array;
- union power_info *power_info;
- int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
- u16 data_offset;
- u8 frev, crev;
- u8 *power_state_offset;
- struct cz_ps *ps;
-
- if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
- &frev, &crev, &data_offset))
- return -EINVAL;
- power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
-
- state_array = (struct _StateArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usStateArrayOffset));
- clock_info_array = (struct _ClockInfoArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
- non_clock_info_array = (struct _NonClockInfoArray *)
- (mode_info->atom_context->bios + data_offset +
- le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
-
- adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) *
- state_array->ucNumEntries, GFP_KERNEL);
-
- if (!adev->pm.dpm.ps)
- return -ENOMEM;
-
- power_state_offset = (u8 *)state_array->states;
- adev->pm.dpm.platform_caps =
- le32_to_cpu(power_info->pplib.ulPlatformCaps);
- adev->pm.dpm.backbias_response_time =
- le16_to_cpu(power_info->pplib.usBackbiasTime);
- adev->pm.dpm.voltage_response_time =
- le16_to_cpu(power_info->pplib.usVoltageTime);
-
- for (i = 0; i < state_array->ucNumEntries; i++) {
- power_state = (union pplib_power_state *)power_state_offset;
- non_clock_array_index = power_state->v2.nonClockInfoIndex;
- non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
- &non_clock_info_array->nonClockInfo[non_clock_array_index];
-
- ps = kzalloc(sizeof(struct cz_ps), GFP_KERNEL);
- if (ps == NULL) {
- for (j = 0; j < i; j++)
- kfree(adev->pm.dpm.ps[j].ps_priv);
- kfree(adev->pm.dpm.ps);
- return -ENOMEM;
- }
-
- adev->pm.dpm.ps[i].ps_priv = ps;
- k = 0;
- for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
- clock_array_index = power_state->v2.clockInfoIndex[j];
- if (clock_array_index >= clock_info_array->ucNumEntries)
- continue;
- if (k >= CZ_MAX_HARDWARE_POWERLEVELS)
- break;
- clock_info = (union pplib_clock_info *)
- &clock_info_array->clockInfo[clock_array_index *
- clock_info_array->ucEntrySize];
- cz_parse_pplib_clock_info(adev, &adev->pm.dpm.ps[i],
- k, clock_info);
- k++;
- }
- cz_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
- non_clock_info,
- non_clock_info_array->ucEntrySize);
- power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
- }
- adev->pm.dpm.num_ps = state_array->ucNumEntries;
-
- return 0;
-}
-
-static int cz_process_firmware_header(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- u32 tmp;
- int ret;
-
- ret = cz_read_smc_sram_dword(adev, SMU8_FIRMWARE_HEADER_LOCATION +
- offsetof(struct SMU8_Firmware_Header,
- DpmTable),
- &tmp, pi->sram_end);
-
- if (ret == 0)
- pi->dpm_table_start = tmp;
-
- return ret;
-}
-
-static int cz_dpm_init(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi;
- int ret, i;
-
- pi = kzalloc(sizeof(struct cz_power_info), GFP_KERNEL);
- if (NULL == pi)
- return -ENOMEM;
-
- adev->pm.dpm.priv = pi;
-
- ret = amdgpu_get_platform_caps(adev);
- if (ret)
- goto err;
-
- ret = amdgpu_parse_extended_power_table(adev);
- if (ret)
- goto err;
-
- pi->sram_end = SMC_RAM_END;
-
- /* set up DPM defaults */
- for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
- pi->active_target[i] = CZ_AT_DFLT;
-
- pi->mgcg_cgtt_local0 = 0x0;
- pi->mgcg_cgtt_local1 = 0x0;
- pi->clock_slow_down_step = 25000;
- pi->skip_clock_slow_down = 1;
- pi->enable_nb_ps_policy = false;
- pi->caps_power_containment = true;
- pi->caps_cac = true;
- pi->didt_enabled = false;
- if (pi->didt_enabled) {
- pi->caps_sq_ramping = true;
- pi->caps_db_ramping = true;
- pi->caps_td_ramping = true;
- pi->caps_tcp_ramping = true;
- }
- if (amdgpu_pp_feature_mask & SCLK_DEEP_SLEEP_MASK)
- pi->caps_sclk_ds = true;
- else
- pi->caps_sclk_ds = false;
-
- pi->voting_clients = 0x00c00033;
- pi->auto_thermal_throttling_enabled = true;
- pi->bapm_enabled = false;
- pi->disable_nb_ps3_in_battery = false;
- pi->voltage_drop_threshold = 0;
- pi->caps_sclk_throttle_low_notification = false;
- pi->gfx_pg_threshold = 500;
- pi->caps_fps = true;
- /* uvd */
- pi->caps_uvd_pg = (adev->pg_flags & AMD_PG_SUPPORT_UVD) ? true : false;
- pi->caps_uvd_dpm = true;
- /* vce */
- pi->caps_vce_pg = (adev->pg_flags & AMD_PG_SUPPORT_VCE) ? true : false;
- pi->caps_vce_dpm = true;
- /* acp */
- pi->caps_acp_pg = (adev->pg_flags & AMD_PG_SUPPORT_ACP) ? true : false;
- pi->caps_acp_dpm = true;
-
- pi->caps_stable_power_state = false;
- pi->nb_dpm_enabled_by_driver = true;
- pi->nb_dpm_enabled = false;
- pi->caps_voltage_island = false;
- /* flags which indicate need to upload pptable */
- pi->need_pptable_upload = true;
-
- ret = cz_parse_sys_info_table(adev);
- if (ret)
- goto err;
-
- cz_patch_voltage_values(adev);
- cz_construct_boot_state(adev);
-
- ret = cz_parse_power_table(adev);
- if (ret)
- goto err;
-
- ret = cz_process_firmware_header(adev);
- if (ret)
- goto err;
-
- pi->dpm_enabled = true;
- pi->uvd_dynamic_pg = false;
-
- return 0;
-err:
- cz_dpm_fini(adev);
- return ret;
-}
-
-static void cz_dpm_fini(struct amdgpu_device *adev)
-{
- int i;
-
- for (i = 0; i < adev->pm.dpm.num_ps; i++)
- kfree(adev->pm.dpm.ps[i].ps_priv);
-
- kfree(adev->pm.dpm.ps);
- kfree(adev->pm.dpm.priv);
- amdgpu_free_extended_power_table(adev);
-}
-
-#define ixSMUSVI_NB_CURRENTVID 0xD8230044
-#define CURRENT_NB_VID_MASK 0xff000000
-#define CURRENT_NB_VID__SHIFT 24
-#define ixSMUSVI_GFX_CURRENTVID 0xD8230048
-#define CURRENT_GFX_VID_MASK 0xff000000
-#define CURRENT_GFX_VID__SHIFT 24
-
-static void
-cz_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
- struct seq_file *m)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
- struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
- u32 sclk_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX),
- TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
- u32 uvd_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
- TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
- u32 vce_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
- TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
- u32 sclk, vclk, dclk, ecclk, tmp;
- u16 vddnb, vddgfx;
-
- if (sclk_index >= NUM_SCLK_LEVELS) {
- seq_printf(m, "invalid sclk dpm profile %d\n", sclk_index);
- } else {
- sclk = table->entries[sclk_index].clk;
- seq_printf(m, "%u sclk: %u\n", sclk_index, sclk);
- }
-
- tmp = (RREG32_SMC(ixSMUSVI_NB_CURRENTVID) &
- CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
- vddnb = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
- tmp = (RREG32_SMC(ixSMUSVI_GFX_CURRENTVID) &
- CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
- vddgfx = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
- seq_printf(m, "vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
-
- seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en");
- if (!pi->uvd_power_gated) {
- if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
- seq_printf(m, "invalid uvd dpm level %d\n", uvd_index);
- } else {
- vclk = uvd_table->entries[uvd_index].vclk;
- dclk = uvd_table->entries[uvd_index].dclk;
- seq_printf(m, "%u uvd vclk: %u dclk: %u\n", uvd_index, vclk, dclk);
- }
- }
-
- seq_printf(m, "vce %sabled\n", pi->vce_power_gated ? "dis" : "en");
- if (!pi->vce_power_gated) {
- if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
- seq_printf(m, "invalid vce dpm level %d\n", vce_index);
- } else {
- ecclk = vce_table->entries[vce_index].ecclk;
- seq_printf(m, "%u vce ecclk: %u\n", vce_index, ecclk);
- }
- }
-}
-
-static void cz_dpm_print_power_state(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- int i;
- struct cz_ps *ps = cz_get_ps(rps);
-
- amdgpu_dpm_print_class_info(rps->class, rps->class2);
- amdgpu_dpm_print_cap_info(rps->caps);
-
- DRM_INFO("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
- for (i = 0; i < ps->num_levels; i++) {
- struct cz_pl *pl = &ps->levels[i];
-
- DRM_INFO("\t\tpower level %d sclk: %u vddc: %u\n",
- i, pl->sclk,
- cz_convert_8bit_index_to_voltage(adev, pl->vddc_index));
- }
-
- amdgpu_dpm_print_ps_status(adev, rps);
-}
-
-static void cz_dpm_set_funcs(struct amdgpu_device *adev);
-
-static int cz_dpm_early_init(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- cz_dpm_set_funcs(adev);
-
- return 0;
-}
-
-
-static int cz_dpm_late_init(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (amdgpu_dpm) {
- int ret;
- /* init the sysfs and debugfs files late */
- ret = amdgpu_pm_sysfs_init(adev);
- if (ret)
- return ret;
-
- /* powerdown unused blocks for now */
- cz_dpm_powergate_uvd(adev, true);
- cz_dpm_powergate_vce(adev, true);
- }
-
- return 0;
-}
-
-static int cz_dpm_sw_init(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- int ret = 0;
- /* fix me to add thermal support TODO */
-
- /* default to balanced state */
- adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
- adev->pm.default_sclk = adev->clock.default_sclk;
- adev->pm.default_mclk = adev->clock.default_mclk;
- adev->pm.current_sclk = adev->clock.default_sclk;
- adev->pm.current_mclk = adev->clock.default_mclk;
- adev->pm.int_thermal_type = THERMAL_TYPE_NONE;
-
- if (amdgpu_dpm == 0)
- return 0;
-
- mutex_lock(&adev->pm.mutex);
- ret = cz_dpm_init(adev);
- if (ret)
- goto dpm_init_failed;
-
- adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
- if (amdgpu_dpm == 1)
- amdgpu_pm_print_power_states(adev);
-
- mutex_unlock(&adev->pm.mutex);
- DRM_INFO("amdgpu: dpm initialized\n");
-
- return 0;
-
-dpm_init_failed:
- cz_dpm_fini(adev);
- mutex_unlock(&adev->pm.mutex);
- DRM_ERROR("amdgpu: dpm initialization failed\n");
-
- return ret;
-}
-
-static int cz_dpm_sw_fini(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- mutex_lock(&adev->pm.mutex);
- amdgpu_pm_sysfs_fini(adev);
- cz_dpm_fini(adev);
- mutex_unlock(&adev->pm.mutex);
-
- return 0;
-}
-
-static void cz_reset_ap_mask(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- pi->active_process_mask = 0;
-}
-
-static int cz_dpm_download_pptable_from_smu(struct amdgpu_device *adev,
- void **table)
-{
- return cz_smu_download_pptable(adev, table);
-}
-
-static int cz_dpm_upload_pptable_to_smu(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct SMU8_Fusion_ClkTable *clock_table;
- struct atom_clock_dividers dividers;
- void *table = NULL;
- uint8_t i = 0;
- int ret = 0;
-
- struct amdgpu_clock_voltage_dependency_table *vddc_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- struct amdgpu_clock_voltage_dependency_table *vddgfx_table =
- &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk;
- struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
- struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
- struct amdgpu_clock_voltage_dependency_table *acp_table =
- &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
-
- if (!pi->need_pptable_upload)
- return 0;
-
- ret = cz_dpm_download_pptable_from_smu(adev, &table);
- if (ret) {
- DRM_ERROR("amdgpu: Failed to get power play table from SMU!\n");
- return -EINVAL;
- }
-
- clock_table = (struct SMU8_Fusion_ClkTable *)table;
- /* patch clock table */
- if (vddc_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
- vddgfx_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
- uvd_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
- vce_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
- acp_table->count > CZ_MAX_HARDWARE_POWERLEVELS) {
- DRM_ERROR("amdgpu: Invalid Clock Voltage Dependency Table!\n");
- return -EINVAL;
- }
-
- for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) {
-
- /* vddc sclk */
- clock_table->SclkBreakdownTable.ClkLevel[i].GnbVid =
- (i < vddc_table->count) ? (uint8_t)vddc_table->entries[i].v : 0;
- clock_table->SclkBreakdownTable.ClkLevel[i].Frequency =
- (i < vddc_table->count) ? vddc_table->entries[i].clk : 0;
- ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
- false, &dividers);
- if (ret)
- return ret;
- clock_table->SclkBreakdownTable.ClkLevel[i].DfsDid =
- (uint8_t)dividers.post_divider;
-
- /* vddgfx sclk */
- clock_table->SclkBreakdownTable.ClkLevel[i].GfxVid =
- (i < vddgfx_table->count) ? (uint8_t)vddgfx_table->entries[i].v : 0;
-
- /* acp breakdown */
- clock_table->AclkBreakdownTable.ClkLevel[i].GfxVid =
- (i < acp_table->count) ? (uint8_t)acp_table->entries[i].v : 0;
- clock_table->AclkBreakdownTable.ClkLevel[i].Frequency =
- (i < acp_table->count) ? acp_table->entries[i].clk : 0;
- ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
- false, &dividers);
- if (ret)
- return ret;
- clock_table->AclkBreakdownTable.ClkLevel[i].DfsDid =
- (uint8_t)dividers.post_divider;
-
- /* uvd breakdown */
- clock_table->VclkBreakdownTable.ClkLevel[i].GfxVid =
- (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
- clock_table->VclkBreakdownTable.ClkLevel[i].Frequency =
- (i < uvd_table->count) ? uvd_table->entries[i].vclk : 0;
- ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- clock_table->VclkBreakdownTable.ClkLevel[i].Frequency,
- false, &dividers);
- if (ret)
- return ret;
- clock_table->VclkBreakdownTable.ClkLevel[i].DfsDid =
- (uint8_t)dividers.post_divider;
-
- clock_table->DclkBreakdownTable.ClkLevel[i].GfxVid =
- (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
- clock_table->DclkBreakdownTable.ClkLevel[i].Frequency =
- (i < uvd_table->count) ? uvd_table->entries[i].dclk : 0;
- ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- clock_table->DclkBreakdownTable.ClkLevel[i].Frequency,
- false, &dividers);
- if (ret)
- return ret;
- clock_table->DclkBreakdownTable.ClkLevel[i].DfsDid =
- (uint8_t)dividers.post_divider;
-
- /* vce breakdown */
- clock_table->EclkBreakdownTable.ClkLevel[i].GfxVid =
- (i < vce_table->count) ? (uint8_t)vce_table->entries[i].v : 0;
- clock_table->EclkBreakdownTable.ClkLevel[i].Frequency =
- (i < vce_table->count) ? vce_table->entries[i].ecclk : 0;
- ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
- clock_table->EclkBreakdownTable.ClkLevel[i].Frequency,
- false, &dividers);
- if (ret)
- return ret;
- clock_table->EclkBreakdownTable.ClkLevel[i].DfsDid =
- (uint8_t)dividers.post_divider;
- }
-
- /* its time to upload to SMU */
- ret = cz_smu_upload_pptable(adev);
- if (ret) {
- DRM_ERROR("amdgpu: Failed to put power play table to SMU!\n");
- return ret;
- }
-
- return 0;
-}
-
-static void cz_init_sclk_limit(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- uint32_t clock = 0, level;
-
- if (!table || !table->count) {
- DRM_ERROR("Invalid Voltage Dependency table.\n");
- return;
- }
-
- pi->sclk_dpm.soft_min_clk = 0;
- pi->sclk_dpm.hard_min_clk = 0;
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxSclkLevel);
- level = cz_get_argument(adev);
- if (level < table->count) {
- clock = table->entries[level].clk;
- } else {
- DRM_ERROR("Invalid SLCK Voltage Dependency table entry.\n");
- clock = table->entries[table->count - 1].clk;
- }
-
- pi->sclk_dpm.soft_max_clk = clock;
- pi->sclk_dpm.hard_max_clk = clock;
-
-}
-
-static void cz_init_uvd_limit(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_uvd_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
- uint32_t clock = 0, level;
-
- if (!table || !table->count) {
- DRM_ERROR("Invalid Voltage Dependency table.\n");
- return;
- }
-
- pi->uvd_dpm.soft_min_clk = 0;
- pi->uvd_dpm.hard_min_clk = 0;
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
- level = cz_get_argument(adev);
- if (level < table->count) {
- clock = table->entries[level].vclk;
- } else {
- DRM_ERROR("Invalid UVD Voltage Dependency table entry.\n");
- clock = table->entries[table->count - 1].vclk;
- }
-
- pi->uvd_dpm.soft_max_clk = clock;
- pi->uvd_dpm.hard_max_clk = clock;
-
-}
-
-static void cz_init_vce_limit(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_vce_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
- uint32_t clock = 0, level;
-
- if (!table || !table->count) {
- DRM_ERROR("Invalid Voltage Dependency table.\n");
- return;
- }
-
- pi->vce_dpm.soft_min_clk = table->entries[0].ecclk;
- pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
- level = cz_get_argument(adev);
- if (level < table->count) {
- clock = table->entries[level].ecclk;
- } else {
- /* future BIOS would fix this error */
- DRM_ERROR("Invalid VCE Voltage Dependency table entry.\n");
- clock = table->entries[table->count - 1].ecclk;
- }
-
- pi->vce_dpm.soft_max_clk = clock;
- pi->vce_dpm.hard_max_clk = clock;
-
-}
-
-static void cz_init_acp_limit(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
- uint32_t clock = 0, level;
-
- if (!table || !table->count) {
- DRM_ERROR("Invalid Voltage Dependency table.\n");
- return;
- }
-
- pi->acp_dpm.soft_min_clk = 0;
- pi->acp_dpm.hard_min_clk = 0;
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxAclkLevel);
- level = cz_get_argument(adev);
- if (level < table->count) {
- clock = table->entries[level].clk;
- } else {
- DRM_ERROR("Invalid ACP Voltage Dependency table entry.\n");
- clock = table->entries[table->count - 1].clk;
- }
-
- pi->acp_dpm.soft_max_clk = clock;
- pi->acp_dpm.hard_max_clk = clock;
-
-}
-
-static void cz_init_pg_state(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- pi->uvd_power_gated = false;
- pi->vce_power_gated = false;
- pi->acp_power_gated = false;
-
-}
-
-static void cz_init_sclk_threshold(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- pi->low_sclk_interrupt_threshold = 0;
-}
-
-static void cz_dpm_setup_asic(struct amdgpu_device *adev)
-{
- cz_reset_ap_mask(adev);
- cz_dpm_upload_pptable_to_smu(adev);
- cz_init_sclk_limit(adev);
- cz_init_uvd_limit(adev);
- cz_init_vce_limit(adev);
- cz_init_acp_limit(adev);
- cz_init_pg_state(adev);
- cz_init_sclk_threshold(adev);
-
-}
-
-static bool cz_check_smu_feature(struct amdgpu_device *adev,
- uint32_t feature)
-{
- uint32_t smu_feature = 0;
- int ret;
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_GetFeatureStatus, 0);
- if (ret) {
- DRM_ERROR("Failed to get SMU features from SMC.\n");
- return false;
- } else {
- smu_feature = cz_get_argument(adev);
- if (feature & smu_feature)
- return true;
- }
-
- return false;
-}
-
-static bool cz_check_for_dpm_enabled(struct amdgpu_device *adev)
-{
- if (cz_check_smu_feature(adev,
- SMU_EnabledFeatureScoreboard_SclkDpmOn))
- return true;
-
- return false;
-}
-
-static void cz_program_voting_clients(struct amdgpu_device *adev)
-{
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, PPCZ_VOTINGRIGHTSCLIENTS_DFLT0);
-}
-
-static void cz_clear_voting_clients(struct amdgpu_device *adev)
-{
- WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, 0);
-}
-
-static int cz_start_dpm(struct amdgpu_device *adev)
-{
- int ret = 0;
-
- if (amdgpu_dpm) {
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_EnableAllSmuFeatures, SCLK_DPM_MASK);
- if (ret) {
- DRM_ERROR("SMU feature: SCLK_DPM enable failed\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int cz_stop_dpm(struct amdgpu_device *adev)
-{
- int ret = 0;
-
- if (amdgpu_dpm && adev->pm.dpm_enabled) {
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_DisableAllSmuFeatures, SCLK_DPM_MASK);
- if (ret) {
- DRM_ERROR("SMU feature: SCLK_DPM disable failed\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static uint32_t cz_get_sclk_level(struct amdgpu_device *adev,
- uint32_t clock, uint16_t msg)
-{
- int i = 0;
- struct amdgpu_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
-
- switch (msg) {
- case PPSMC_MSG_SetSclkSoftMin:
- case PPSMC_MSG_SetSclkHardMin:
- for (i = 0; i < table->count; i++)
- if (clock <= table->entries[i].clk)
- break;
- if (i == table->count)
- i = table->count - 1;
- break;
- case PPSMC_MSG_SetSclkSoftMax:
- case PPSMC_MSG_SetSclkHardMax:
- for (i = table->count - 1; i >= 0; i--)
- if (clock >= table->entries[i].clk)
- break;
- if (i < 0)
- i = 0;
- break;
- default:
- break;
- }
-
- return i;
-}
-
-static uint32_t cz_get_eclk_level(struct amdgpu_device *adev,
- uint32_t clock, uint16_t msg)
-{
- int i = 0;
- struct amdgpu_vce_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
-
- if (table->count == 0)
- return 0;
-
- switch (msg) {
- case PPSMC_MSG_SetEclkSoftMin:
- case PPSMC_MSG_SetEclkHardMin:
- for (i = 0; i < table->count-1; i++)
- if (clock <= table->entries[i].ecclk)
- break;
- break;
- case PPSMC_MSG_SetEclkSoftMax:
- case PPSMC_MSG_SetEclkHardMax:
- for (i = table->count - 1; i > 0; i--)
- if (clock >= table->entries[i].ecclk)
- break;
- break;
- default:
- break;
- }
-
- return i;
-}
-
-static uint32_t cz_get_uvd_level(struct amdgpu_device *adev,
- uint32_t clock, uint16_t msg)
-{
- int i = 0;
- struct amdgpu_uvd_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
-
- switch (msg) {
- case PPSMC_MSG_SetUvdSoftMin:
- case PPSMC_MSG_SetUvdHardMin:
- for (i = 0; i < table->count; i++)
- if (clock <= table->entries[i].vclk)
- break;
- if (i == table->count)
- i = table->count - 1;
- break;
- case PPSMC_MSG_SetUvdSoftMax:
- case PPSMC_MSG_SetUvdHardMax:
- for (i = table->count - 1; i >= 0; i--)
- if (clock >= table->entries[i].vclk)
- break;
- if (i < 0)
- i = 0;
- break;
- default:
- break;
- }
-
- return i;
-}
-
-static int cz_program_bootup_state(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- uint32_t soft_min_clk = 0;
- uint32_t soft_max_clk = 0;
- int ret = 0;
-
- pi->sclk_dpm.soft_min_clk = pi->sys_info.bootup_sclk;
- pi->sclk_dpm.soft_max_clk = pi->sys_info.bootup_sclk;
-
- soft_min_clk = cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_min_clk,
- PPSMC_MSG_SetSclkSoftMin);
- soft_max_clk = cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_max_clk,
- PPSMC_MSG_SetSclkSoftMax);
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMin, soft_min_clk);
- if (ret)
- return -EINVAL;
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMax, soft_max_clk);
- if (ret)
- return -EINVAL;
-
- return 0;
-}
-
-/* TODO */
-static int cz_disable_cgpg(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-/* TODO */
-static int cz_enable_cgpg(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-/* TODO */
-static int cz_program_pt_config_registers(struct amdgpu_device *adev)
-{
- return 0;
-}
-
-static void cz_do_enable_didt(struct amdgpu_device *adev, bool enable)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- uint32_t reg = 0;
-
- if (pi->caps_sq_ramping) {
- reg = RREG32_DIDT(ixDIDT_SQ_CTRL0);
- if (enable)
- reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 1);
- else
- reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 0);
- WREG32_DIDT(ixDIDT_SQ_CTRL0, reg);
- }
- if (pi->caps_db_ramping) {
- reg = RREG32_DIDT(ixDIDT_DB_CTRL0);
- if (enable)
- reg = REG_SET_FIELD(reg, DIDT_DB_CTRL0, DIDT_CTRL_EN, 1);
- else
- reg = REG_SET_FIELD(reg, DIDT_DB_CTRL0, DIDT_CTRL_EN, 0);
- WREG32_DIDT(ixDIDT_DB_CTRL0, reg);
- }
- if (pi->caps_td_ramping) {
- reg = RREG32_DIDT(ixDIDT_TD_CTRL0);
- if (enable)
- reg = REG_SET_FIELD(reg, DIDT_TD_CTRL0, DIDT_CTRL_EN, 1);
- else
- reg = REG_SET_FIELD(reg, DIDT_TD_CTRL0, DIDT_CTRL_EN, 0);
- WREG32_DIDT(ixDIDT_TD_CTRL0, reg);
- }
- if (pi->caps_tcp_ramping) {
- reg = RREG32_DIDT(ixDIDT_TCP_CTRL0);
- if (enable)
- reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 1);
- else
- reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 0);
- WREG32_DIDT(ixDIDT_TCP_CTRL0, reg);
- }
-
-}
-
-static int cz_enable_didt(struct amdgpu_device *adev, bool enable)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret;
-
- if (pi->caps_sq_ramping || pi->caps_db_ramping ||
- pi->caps_td_ramping || pi->caps_tcp_ramping) {
- if (adev->gfx.gfx_current_status != AMDGPU_GFX_SAFE_MODE) {
- ret = cz_disable_cgpg(adev);
- if (ret) {
- DRM_ERROR("Pre Di/Dt disable cg/pg failed\n");
- return -EINVAL;
- }
- adev->gfx.gfx_current_status = AMDGPU_GFX_SAFE_MODE;
- }
-
- ret = cz_program_pt_config_registers(adev);
- if (ret) {
- DRM_ERROR("Di/Dt config failed\n");
- return -EINVAL;
- }
- cz_do_enable_didt(adev, enable);
-
- if (adev->gfx.gfx_current_status == AMDGPU_GFX_SAFE_MODE) {
- ret = cz_enable_cgpg(adev);
- if (ret) {
- DRM_ERROR("Post Di/Dt enable cg/pg failed\n");
- return -EINVAL;
- }
- adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
- }
- }
-
- return 0;
-}
-
-/* TODO */
-static void cz_reset_acp_boot_level(struct amdgpu_device *adev)
-{
-}
-
-static void cz_update_current_ps(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct cz_ps *ps = cz_get_ps(rps);
-
- pi->current_ps = *ps;
- pi->current_rps = *rps;
- pi->current_rps.ps_priv = &pi->current_ps;
- adev->pm.dpm.current_ps = &pi->current_rps;
-
-}
-
-static void cz_update_requested_ps(struct amdgpu_device *adev,
- struct amdgpu_ps *rps)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct cz_ps *ps = cz_get_ps(rps);
-
- pi->requested_ps = *ps;
- pi->requested_rps = *rps;
- pi->requested_rps.ps_priv = &pi->requested_ps;
- adev->pm.dpm.requested_ps = &pi->requested_rps;
-
-}
-
-/* PP arbiter support needed TODO */
-static void cz_apply_state_adjust_rules(struct amdgpu_device *adev,
- struct amdgpu_ps *new_rps,
- struct amdgpu_ps *old_rps)
-{
- struct cz_ps *ps = cz_get_ps(new_rps);
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_and_voltage_limits *limits =
- &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- /* 10kHz memory clock */
- uint32_t mclk = 0;
-
- ps->force_high = false;
- ps->need_dfs_bypass = true;
- pi->video_start = new_rps->dclk || new_rps->vclk ||
- new_rps->evclk || new_rps->ecclk;
-
- if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
- ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
- pi->battery_state = true;
- else
- pi->battery_state = false;
-
- if (pi->caps_stable_power_state)
- mclk = limits->mclk;
-
- if (mclk > pi->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORY_CLOCK - 1])
- ps->force_high = true;
-
-}
-
-static int cz_dpm_enable(struct amdgpu_device *adev)
-{
- const char *chip_name;
- int ret = 0;
-
- /* renable will hang up SMU, so check first */
- if (cz_check_for_dpm_enabled(adev))
- return -EINVAL;
-
- cz_program_voting_clients(adev);
-
- switch (adev->asic_type) {
- case CHIP_CARRIZO:
- chip_name = "carrizo";
- break;
- case CHIP_STONEY:
- chip_name = "stoney";
- break;
- default:
- BUG();
- }
-
-
- ret = cz_start_dpm(adev);
- if (ret) {
- DRM_ERROR("%s DPM enable failed\n", chip_name);
- return -EINVAL;
- }
-
- ret = cz_program_bootup_state(adev);
- if (ret) {
- DRM_ERROR("%s bootup state program failed\n", chip_name);
- return -EINVAL;
- }
-
- ret = cz_enable_didt(adev, true);
- if (ret) {
- DRM_ERROR("%s enable di/dt failed\n", chip_name);
- return -EINVAL;
- }
-
- cz_reset_acp_boot_level(adev);
- cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
-
- return 0;
-}
-
-static int cz_dpm_hw_init(void *handle)
-{
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- int ret = 0;
-
- mutex_lock(&adev->pm.mutex);
-
- /* smu init only needs to be called at startup, not resume.
- * It should be in sw_init, but requires the fw info gathered
- * in sw_init from other IP modules.
- */
- ret = cz_smu_init(adev);
- if (ret) {
- DRM_ERROR("amdgpu: smc initialization failed\n");
- mutex_unlock(&adev->pm.mutex);
- return ret;
- }
-
- /* do the actual fw loading */
- ret = cz_smu_start(adev);
- if (ret) {
- DRM_ERROR("amdgpu: smc start failed\n");
- mutex_unlock(&adev->pm.mutex);
- return ret;
- }
-
- if (!amdgpu_dpm) {
- adev->pm.dpm_enabled = false;
- mutex_unlock(&adev->pm.mutex);
- return ret;
- }
-
- /* cz dpm setup asic */
- cz_dpm_setup_asic(adev);
-
- /* cz dpm enable */
- ret = cz_dpm_enable(adev);
- if (ret)
- adev->pm.dpm_enabled = false;
- else
- adev->pm.dpm_enabled = true;
-
- mutex_unlock(&adev->pm.mutex);
-
- return 0;
-}
-
-static int cz_dpm_disable(struct amdgpu_device *adev)
-{
- int ret = 0;
-
- if (!cz_check_for_dpm_enabled(adev))
- return -EINVAL;
-
- ret = cz_enable_didt(adev, false);
- if (ret) {
- DRM_ERROR("disable di/dt failed\n");
- return -EINVAL;
- }
-
- /* powerup blocks */
- cz_dpm_powergate_uvd(adev, false);
- cz_dpm_powergate_vce(adev, false);
-
- cz_clear_voting_clients(adev);
- cz_stop_dpm(adev);
- cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
-
- return 0;
-}
-
-static int cz_dpm_hw_fini(void *handle)
-{
- int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- mutex_lock(&adev->pm.mutex);
-
- /* smu fini only needs to be called at teardown, not suspend.
- * It should be in sw_fini, but we put it here for symmetry
- * with smu init.
- */
- cz_smu_fini(adev);
-
- if (adev->pm.dpm_enabled) {
- ret = cz_dpm_disable(adev);
-
- adev->pm.dpm.current_ps =
- adev->pm.dpm.requested_ps =
- adev->pm.dpm.boot_ps;
- }
-
- adev->pm.dpm_enabled = false;
-
- mutex_unlock(&adev->pm.mutex);
-
- return ret;
-}
-
-static int cz_dpm_suspend(void *handle)
-{
- int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (adev->pm.dpm_enabled) {
- mutex_lock(&adev->pm.mutex);
-
- ret = cz_dpm_disable(adev);
-
- adev->pm.dpm.current_ps =
- adev->pm.dpm.requested_ps =
- adev->pm.dpm.boot_ps;
-
- mutex_unlock(&adev->pm.mutex);
- }
-
- return ret;
-}
-
-static int cz_dpm_resume(void *handle)
-{
- int ret = 0;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- mutex_lock(&adev->pm.mutex);
-
- /* do the actual fw loading */
- ret = cz_smu_start(adev);
- if (ret) {
- DRM_ERROR("amdgpu: smc start failed\n");
- mutex_unlock(&adev->pm.mutex);
- return ret;
- }
-
- if (!amdgpu_dpm) {
- adev->pm.dpm_enabled = false;
- mutex_unlock(&adev->pm.mutex);
- return ret;
- }
-
- /* cz dpm setup asic */
- cz_dpm_setup_asic(adev);
-
- /* cz dpm enable */
- ret = cz_dpm_enable(adev);
- if (ret)
- adev->pm.dpm_enabled = false;
- else
- adev->pm.dpm_enabled = true;
-
- mutex_unlock(&adev->pm.mutex);
- /* upon resume, re-compute the clocks */
- if (adev->pm.dpm_enabled)
- amdgpu_pm_compute_clocks(adev);
-
- return 0;
-}
-
-static int cz_dpm_set_clockgating_state(void *handle,
- enum amd_clockgating_state state)
-{
- return 0;
-}
-
-static int cz_dpm_set_powergating_state(void *handle,
- enum amd_powergating_state state)
-{
- return 0;
-}
-
-static int cz_dpm_get_temperature(struct amdgpu_device *adev)
-{
- int actual_temp = 0;
- uint32_t val = RREG32_SMC(ixTHM_TCON_CUR_TMP);
- uint32_t temp = REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP);
-
- if (REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL))
- actual_temp = 1000 * ((temp / 8) - 49);
- else
- actual_temp = 1000 * (temp / 8);
-
- return actual_temp;
-}
-
-static int cz_dpm_pre_set_power_state(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_ps requested_ps = *adev->pm.dpm.requested_ps;
- struct amdgpu_ps *new_ps = &requested_ps;
-
- cz_update_requested_ps(adev, new_ps);
- cz_apply_state_adjust_rules(adev, &pi->requested_rps,
- &pi->current_rps);
-
- return 0;
-}
-
-static int cz_dpm_update_sclk_limit(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_and_voltage_limits *limits =
- &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
- uint32_t clock, stable_ps_clock = 0;
-
- clock = pi->sclk_dpm.soft_min_clk;
-
- if (pi->caps_stable_power_state) {
- stable_ps_clock = limits->sclk * 75 / 100;
- if (clock < stable_ps_clock)
- clock = stable_ps_clock;
- }
-
- if (clock != pi->sclk_dpm.soft_min_clk) {
- pi->sclk_dpm.soft_min_clk = clock;
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMin,
- cz_get_sclk_level(adev, clock,
- PPSMC_MSG_SetSclkSoftMin));
- }
-
- if (pi->caps_stable_power_state &&
- pi->sclk_dpm.soft_max_clk != clock) {
- pi->sclk_dpm.soft_max_clk = clock;
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMax,
- cz_get_sclk_level(adev, clock,
- PPSMC_MSG_SetSclkSoftMax));
- } else {
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMax,
- cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_max_clk,
- PPSMC_MSG_SetSclkSoftMax));
- }
-
- return 0;
-}
-
-static int cz_dpm_set_deep_sleep_sclk_threshold(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- if (pi->caps_sclk_ds) {
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetMinDeepSleepSclk,
- CZ_MIN_DEEP_SLEEP_SCLK);
- }
-
- return 0;
-}
-
-/* ?? without dal support, is this still needed in setpowerstate list*/
-static int cz_dpm_set_watermark_threshold(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetWatermarkFrequency,
- pi->sclk_dpm.soft_max_clk);
-
- return 0;
-}
-
-static int cz_dpm_enable_nbdpm(struct amdgpu_device *adev)
-{
- int ret = 0;
- struct cz_power_info *pi = cz_get_pi(adev);
-
- /* also depend on dal NBPStateDisableRequired */
- if (pi->nb_dpm_enabled_by_driver && !pi->nb_dpm_enabled) {
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_EnableAllSmuFeatures,
- NB_DPM_MASK);
- if (ret) {
- DRM_ERROR("amdgpu: nb dpm enable failed\n");
- return ret;
- }
- pi->nb_dpm_enabled = true;
- }
-
- return ret;
-}
-
-static void cz_dpm_nbdpm_lm_pstate_enable(struct amdgpu_device *adev,
- bool enable)
-{
- if (enable)
- cz_send_msg_to_smc(adev, PPSMC_MSG_EnableLowMemoryPstate);
- else
- cz_send_msg_to_smc(adev, PPSMC_MSG_DisableLowMemoryPstate);
-
-}
-
-static int cz_dpm_update_low_memory_pstate(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct cz_ps *ps = &pi->requested_ps;
-
- if (pi->sys_info.nb_dpm_enable) {
- if (ps->force_high)
- cz_dpm_nbdpm_lm_pstate_enable(adev, false);
- else
- cz_dpm_nbdpm_lm_pstate_enable(adev, true);
- }
-
- return 0;
-}
-
-/* with dpm enabled */
-static int cz_dpm_set_power_state(struct amdgpu_device *adev)
-{
- cz_dpm_update_sclk_limit(adev);
- cz_dpm_set_deep_sleep_sclk_threshold(adev);
- cz_dpm_set_watermark_threshold(adev);
- cz_dpm_enable_nbdpm(adev);
- cz_dpm_update_low_memory_pstate(adev);
-
- return 0;
-}
-
-static void cz_dpm_post_set_power_state(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_ps *ps = &pi->requested_rps;
-
- cz_update_current_ps(adev, ps);
-}
-
-static int cz_dpm_force_highest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->sclk_dpm.soft_min_clk != pi->sclk_dpm.soft_max_clk) {
- pi->sclk_dpm.soft_min_clk =
- pi->sclk_dpm.soft_max_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMin,
- cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_min_clk,
- PPSMC_MSG_SetSclkSoftMin));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static int cz_dpm_force_lowest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->sclk_dpm.soft_max_clk != pi->sclk_dpm.soft_min_clk) {
- pi->sclk_dpm.soft_max_clk = pi->sclk_dpm.soft_min_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMax,
- cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_max_clk,
- PPSMC_MSG_SetSclkSoftMax));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static uint32_t cz_dpm_get_max_sclk_level(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- if (!pi->max_sclk_level) {
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxSclkLevel);
- pi->max_sclk_level = cz_get_argument(adev) + 1;
- }
-
- if (pi->max_sclk_level > CZ_MAX_HARDWARE_POWERLEVELS) {
- DRM_ERROR("Invalid max sclk level!\n");
- return -EINVAL;
- }
-
- return pi->max_sclk_level;
-}
-
-static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_clock_voltage_dependency_table *dep_table =
- &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
- uint32_t level = 0;
- int ret = 0;
-
- pi->sclk_dpm.soft_min_clk = dep_table->entries[0].clk;
- level = cz_dpm_get_max_sclk_level(adev) - 1;
- if (level < dep_table->count)
- pi->sclk_dpm.soft_max_clk = dep_table->entries[level].clk;
- else
- pi->sclk_dpm.soft_max_clk =
- dep_table->entries[dep_table->count - 1].clk;
-
- /* get min/max sclk soft value
- * notify SMU to execute */
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMin,
- cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_min_clk,
- PPSMC_MSG_SetSclkSoftMin));
- if (ret)
- return ret;
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetSclkSoftMax,
- cz_get_sclk_level(adev,
- pi->sclk_dpm.soft_max_clk,
- PPSMC_MSG_SetSclkSoftMax));
- if (ret)
- return ret;
-
- DRM_DEBUG("DPM unforce state min=%d, max=%d.\n",
- pi->sclk_dpm.soft_min_clk,
- pi->sclk_dpm.soft_max_clk);
-
- return 0;
-}
-
-static int cz_dpm_uvd_force_highest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->uvd_dpm.soft_min_clk != pi->uvd_dpm.soft_max_clk) {
- pi->uvd_dpm.soft_min_clk =
- pi->uvd_dpm.soft_max_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetUvdSoftMin,
- cz_get_uvd_level(adev,
- pi->uvd_dpm.soft_min_clk,
- PPSMC_MSG_SetUvdSoftMin));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static int cz_dpm_uvd_force_lowest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->uvd_dpm.soft_max_clk != pi->uvd_dpm.soft_min_clk) {
- pi->uvd_dpm.soft_max_clk = pi->uvd_dpm.soft_min_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetUvdSoftMax,
- cz_get_uvd_level(adev,
- pi->uvd_dpm.soft_max_clk,
- PPSMC_MSG_SetUvdSoftMax));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static uint32_t cz_dpm_get_max_uvd_level(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- if (!pi->max_uvd_level) {
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
- pi->max_uvd_level = cz_get_argument(adev) + 1;
- }
-
- if (pi->max_uvd_level > CZ_MAX_HARDWARE_POWERLEVELS) {
- DRM_ERROR("Invalid max uvd level!\n");
- return -EINVAL;
- }
-
- return pi->max_uvd_level;
-}
-
-static int cz_dpm_unforce_uvd_dpm_levels(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_uvd_clock_voltage_dependency_table *dep_table =
- &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
- uint32_t level = 0;
- int ret = 0;
-
- pi->uvd_dpm.soft_min_clk = dep_table->entries[0].vclk;
- level = cz_dpm_get_max_uvd_level(adev) - 1;
- if (level < dep_table->count)
- pi->uvd_dpm.soft_max_clk = dep_table->entries[level].vclk;
- else
- pi->uvd_dpm.soft_max_clk =
- dep_table->entries[dep_table->count - 1].vclk;
-
- /* get min/max sclk soft value
- * notify SMU to execute */
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetUvdSoftMin,
- cz_get_uvd_level(adev,
- pi->uvd_dpm.soft_min_clk,
- PPSMC_MSG_SetUvdSoftMin));
- if (ret)
- return ret;
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetUvdSoftMax,
- cz_get_uvd_level(adev,
- pi->uvd_dpm.soft_max_clk,
- PPSMC_MSG_SetUvdSoftMax));
- if (ret)
- return ret;
-
- DRM_DEBUG("DPM uvd unforce state min=%d, max=%d.\n",
- pi->uvd_dpm.soft_min_clk,
- pi->uvd_dpm.soft_max_clk);
-
- return 0;
-}
-
-static int cz_dpm_vce_force_highest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->vce_dpm.soft_min_clk != pi->vce_dpm.soft_max_clk) {
- pi->vce_dpm.soft_min_clk =
- pi->vce_dpm.soft_max_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetEclkSoftMin,
- cz_get_eclk_level(adev,
- pi->vce_dpm.soft_min_clk,
- PPSMC_MSG_SetEclkSoftMin));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static int cz_dpm_vce_force_lowest(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (pi->vce_dpm.soft_max_clk != pi->vce_dpm.soft_min_clk) {
- pi->vce_dpm.soft_max_clk = pi->vce_dpm.soft_min_clk;
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetEclkSoftMax,
- cz_get_uvd_level(adev,
- pi->vce_dpm.soft_max_clk,
- PPSMC_MSG_SetEclkSoftMax));
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static uint32_t cz_dpm_get_max_vce_level(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- if (!pi->max_vce_level) {
- cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
- pi->max_vce_level = cz_get_argument(adev) + 1;
- }
-
- if (pi->max_vce_level > CZ_MAX_HARDWARE_POWERLEVELS) {
- DRM_ERROR("Invalid max vce level!\n");
- return -EINVAL;
- }
-
- return pi->max_vce_level;
-}
-
-static int cz_dpm_unforce_vce_dpm_levels(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_vce_clock_voltage_dependency_table *dep_table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
- uint32_t level = 0;
- int ret = 0;
-
- pi->vce_dpm.soft_min_clk = dep_table->entries[0].ecclk;
- level = cz_dpm_get_max_vce_level(adev) - 1;
- if (level < dep_table->count)
- pi->vce_dpm.soft_max_clk = dep_table->entries[level].ecclk;
- else
- pi->vce_dpm.soft_max_clk =
- dep_table->entries[dep_table->count - 1].ecclk;
-
- /* get min/max sclk soft value
- * notify SMU to execute */
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetEclkSoftMin,
- cz_get_eclk_level(adev,
- pi->vce_dpm.soft_min_clk,
- PPSMC_MSG_SetEclkSoftMin));
- if (ret)
- return ret;
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetEclkSoftMax,
- cz_get_eclk_level(adev,
- pi->vce_dpm.soft_max_clk,
- PPSMC_MSG_SetEclkSoftMax));
- if (ret)
- return ret;
-
- DRM_DEBUG("DPM vce unforce state min=%d, max=%d.\n",
- pi->vce_dpm.soft_min_clk,
- pi->vce_dpm.soft_max_clk);
-
- return 0;
-}
-
-static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
- enum amdgpu_dpm_forced_level level)
-{
- int ret = 0;
-
- switch (level) {
- case AMDGPU_DPM_FORCED_LEVEL_HIGH:
- /* sclk */
- ret = cz_dpm_unforce_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_force_highest(adev);
- if (ret)
- return ret;
-
- /* uvd */
- ret = cz_dpm_unforce_uvd_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_uvd_force_highest(adev);
- if (ret)
- return ret;
-
- /* vce */
- ret = cz_dpm_unforce_vce_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_vce_force_highest(adev);
- if (ret)
- return ret;
- break;
- case AMDGPU_DPM_FORCED_LEVEL_LOW:
- /* sclk */
- ret = cz_dpm_unforce_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_force_lowest(adev);
- if (ret)
- return ret;
-
- /* uvd */
- ret = cz_dpm_unforce_uvd_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_uvd_force_lowest(adev);
- if (ret)
- return ret;
-
- /* vce */
- ret = cz_dpm_unforce_vce_dpm_levels(adev);
- if (ret)
- return ret;
- ret = cz_dpm_vce_force_lowest(adev);
- if (ret)
- return ret;
- break;
- case AMDGPU_DPM_FORCED_LEVEL_AUTO:
- /* sclk */
- ret = cz_dpm_unforce_dpm_levels(adev);
- if (ret)
- return ret;
-
- /* uvd */
- ret = cz_dpm_unforce_uvd_dpm_levels(adev);
- if (ret)
- return ret;
-
- /* vce */
- ret = cz_dpm_unforce_vce_dpm_levels(adev);
- if (ret)
- return ret;
- break;
- default:
- break;
- }
-
- adev->pm.dpm.forced_level = level;
-
- return ret;
-}
-
-/* fix me, display configuration change lists here
- * mostly dal related*/
-static void cz_dpm_display_configuration_changed(struct amdgpu_device *adev)
-{
-}
-
-static uint32_t cz_dpm_get_sclk(struct amdgpu_device *adev, bool low)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct cz_ps *requested_state = cz_get_ps(&pi->requested_rps);
-
- if (low)
- return requested_state->levels[0].sclk;
- else
- return requested_state->levels[requested_state->num_levels - 1].sclk;
-
-}
-
-static uint32_t cz_dpm_get_mclk(struct amdgpu_device *adev, bool low)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- return pi->sys_info.bootup_uma_clk;
-}
-
-static int cz_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (enable && pi->caps_uvd_dpm ) {
- pi->dpm_flags |= DPMFlags_UVD_Enabled;
- DRM_DEBUG("UVD DPM Enabled.\n");
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_EnableAllSmuFeatures, UVD_DPM_MASK);
- } else {
- pi->dpm_flags &= ~DPMFlags_UVD_Enabled;
- DRM_DEBUG("UVD DPM Stopped\n");
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_DisableAllSmuFeatures, UVD_DPM_MASK);
- }
-
- return ret;
-}
-
-static int cz_update_uvd_dpm(struct amdgpu_device *adev, bool gate)
-{
- return cz_enable_uvd_dpm(adev, !gate);
-}
-
-
-static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret;
-
- if (pi->uvd_power_gated == gate)
- return;
-
- pi->uvd_power_gated = gate;
-
- if (gate) {
- if (pi->caps_uvd_pg) {
- ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_CG_STATE_GATE);
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating failed to set clockgating state\n");
- return;
- }
-
- /* shutdown the UVD block */
- ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_PG_STATE_GATE);
-
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating failed to set powergating state\n");
- return;
- }
- }
- cz_update_uvd_dpm(adev, gate);
- if (pi->caps_uvd_pg) {
- /* power off the UVD block */
- ret = cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF);
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating failed to send SMU PowerOFF message\n");
- return;
- }
- }
- } else {
- if (pi->caps_uvd_pg) {
- /* power on the UVD block */
- if (pi->uvd_dynamic_pg)
- ret = cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1);
- else
- ret = cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0);
-
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating Failed to send SMU PowerON message\n");
- return;
- }
-
- /* re-init the UVD block */
- ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_PG_STATE_UNGATE);
-
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating Failed to set powergating state\n");
- return;
- }
-
- ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
- AMD_CG_STATE_UNGATE);
- if (ret) {
- DRM_ERROR("UVD DPM Power Gating Failed to set clockgating state\n");
- return;
- }
- }
- cz_update_uvd_dpm(adev, gate);
- }
-}
-
-static int cz_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- int ret = 0;
-
- if (enable && pi->caps_vce_dpm) {
- pi->dpm_flags |= DPMFlags_VCE_Enabled;
- DRM_DEBUG("VCE DPM Enabled.\n");
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_EnableAllSmuFeatures, VCE_DPM_MASK);
-
- } else {
- pi->dpm_flags &= ~DPMFlags_VCE_Enabled;
- DRM_DEBUG("VCE DPM Stopped\n");
-
- ret = cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_DisableAllSmuFeatures, VCE_DPM_MASK);
- }
-
- return ret;
-}
-
-static int cz_update_vce_dpm(struct amdgpu_device *adev)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
- struct amdgpu_vce_clock_voltage_dependency_table *table =
- &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
-
- /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
- if (pi->caps_stable_power_state) {
- pi->vce_dpm.hard_min_clk = table->entries[table->count-1].ecclk;
- } else { /* non-stable p-state cases. without vce.Arbiter.EcclkHardMin */
- /* leave it as set by user */
- /*pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;*/
- }
-
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetEclkHardMin,
- cz_get_eclk_level(adev,
- pi->vce_dpm.hard_min_clk,
- PPSMC_MSG_SetEclkHardMin));
- return 0;
-}
-
-static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
-{
- struct cz_power_info *pi = cz_get_pi(adev);
-
- if (pi->caps_vce_pg) {
- if (pi->vce_power_gated != gate) {
- if (gate) {
- /* disable clockgating so we can properly shut down the block */
- amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
- AMD_CG_STATE_UNGATE);
- /* shutdown the VCE block */
- amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
- AMD_PG_STATE_GATE);
-
- cz_enable_vce_dpm(adev, false);
- cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF);
- pi->vce_power_gated = true;
- } else {
- cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerON);
- pi->vce_power_gated = false;
-
- /* re-init the VCE block */
- amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
- AMD_PG_STATE_UNGATE);
- /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */
- amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
- AMD_CG_STATE_GATE);
-
- cz_update_vce_dpm(adev);
- cz_enable_vce_dpm(adev, true);
- }
- } else {
- if (! pi->vce_power_gated) {
- cz_update_vce_dpm(adev);
- }
- }
- } else { /*pi->caps_vce_pg*/
- pi->vce_power_gated = gate;
- cz_update_vce_dpm(adev);
- cz_enable_vce_dpm(adev, !gate);
- }
-}
-
-static int cz_check_state_equal(struct amdgpu_device *adev,
- struct amdgpu_ps *cps,
- struct amdgpu_ps *rps,
- bool *equal)
-{
- if (equal == NULL)
- return -EINVAL;
-
- *equal = false;
- return 0;
-}
-
-const struct amd_ip_funcs cz_dpm_ip_funcs = {
- .name = "cz_dpm",
- .early_init = cz_dpm_early_init,
- .late_init = cz_dpm_late_init,
- .sw_init = cz_dpm_sw_init,
- .sw_fini = cz_dpm_sw_fini,
- .hw_init = cz_dpm_hw_init,
- .hw_fini = cz_dpm_hw_fini,
- .suspend = cz_dpm_suspend,
- .resume = cz_dpm_resume,
- .is_idle = NULL,
- .wait_for_idle = NULL,
- .soft_reset = NULL,
- .set_clockgating_state = cz_dpm_set_clockgating_state,
- .set_powergating_state = cz_dpm_set_powergating_state,
-};
-
-static const struct amdgpu_dpm_funcs cz_dpm_funcs = {
- .get_temperature = cz_dpm_get_temperature,
- .pre_set_power_state = cz_dpm_pre_set_power_state,
- .set_power_state = cz_dpm_set_power_state,
- .post_set_power_state = cz_dpm_post_set_power_state,
- .display_configuration_changed = cz_dpm_display_configuration_changed,
- .get_sclk = cz_dpm_get_sclk,
- .get_mclk = cz_dpm_get_mclk,
- .print_power_state = cz_dpm_print_power_state,
- .debugfs_print_current_performance_level =
- cz_dpm_debugfs_print_current_performance_level,
- .force_performance_level = cz_dpm_force_dpm_level,
- .vblank_too_short = NULL,
- .powergate_uvd = cz_dpm_powergate_uvd,
- .powergate_vce = cz_dpm_powergate_vce,
- .check_state_equal = cz_check_state_equal,
-};
-
-static void cz_dpm_set_funcs(struct amdgpu_device *adev)
-{
- if (NULL == adev->pm.funcs)
- adev->pm.funcs = &cz_dpm_funcs;
-}
-
-const struct amdgpu_ip_block_version cz_dpm_ip_block =
-{
- .type = AMD_IP_BLOCK_TYPE_SMC,
- .major = 8,
- .minor = 0,
- .rev = 0,
- .funcs = &cz_dpm_ip_funcs,
-};
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
deleted file mode 100644
index 5df8c1faab51..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __CZ_DPM_H__
-#define __CZ_DPM_H__
-
-#include "smu8_fusion.h"
-
-#define CZ_AT_DFLT 30
-#define CZ_NUM_NBPSTATES 4
-#define CZ_NUM_NBPMEMORY_CLOCK 2
-#define CZ_MAX_HARDWARE_POWERLEVELS 8
-#define CZ_MAX_DISPLAY_CLOCK_LEVEL 8
-#define CZ_MAX_DISPLAYPHY_IDS 10
-
-#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
-
-#define SMC_RAM_END 0x40000
-
-#define DPMFlags_SCLK_Enabled 0x00000001
-#define DPMFlags_UVD_Enabled 0x00000002
-#define DPMFlags_VCE_Enabled 0x00000004
-#define DPMFlags_ACP_Enabled 0x00000008
-#define DPMFlags_ForceHighestValid 0x40000000
-#define DPMFlags_Debug 0x80000000
-
-/* Do not change the following, it is also defined in SMU8.h */
-#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001
-#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000
-#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000
-#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000
-
-/* temporary solution to SetMinDeepSleepSclk
- * should indicate by display adaptor
- * 10k Hz unit*/
-#define CZ_MIN_DEEP_SLEEP_SCLK 800
-
-enum cz_pt_config_reg_type {
- CZ_CONFIGREG_MMR = 0,
- CZ_CONFIGREG_SMC_IND,
- CZ_CONFIGREG_DIDT_IND,
- CZ_CONFIGREG_CACHE,
- CZ_CONFIGREG_MAX
-};
-
-struct cz_pt_config_reg {
- uint32_t offset;
- uint32_t mask;
- uint32_t shift;
- uint32_t value;
- enum cz_pt_config_reg_type type;
-};
-
-struct cz_dpm_entry {
- uint32_t soft_min_clk;
- uint32_t hard_min_clk;
- uint32_t soft_max_clk;
- uint32_t hard_max_clk;
-};
-
-struct cz_pl {
- uint32_t sclk;
- uint8_t vddc_index;
- uint8_t ds_divider_index;
- uint8_t ss_divider_index;
- uint8_t allow_gnb_slow;
- uint8_t force_nbp_state;
- uint8_t display_wm;
- uint8_t vce_wm;
-};
-
-struct cz_ps {
- struct cz_pl levels[CZ_MAX_HARDWARE_POWERLEVELS];
- uint32_t num_levels;
- bool need_dfs_bypass;
- uint8_t dpm0_pg_nb_ps_lo;
- uint8_t dpm0_pg_nb_ps_hi;
- uint8_t dpmx_nb_ps_lo;
- uint8_t dpmx_nb_ps_hi;
- bool force_high;
-};
-
-struct cz_displayphy_entry {
- uint8_t phy_present;
- uint8_t active_lane_mapping;
- uint8_t display_conf_type;
- uint8_t num_active_lanes;
-};
-
-struct cz_displayphy_info {
- bool phy_access_initialized;
- struct cz_displayphy_entry entries[CZ_MAX_DISPLAYPHY_IDS];
-};
-
-struct cz_sys_info {
- uint32_t bootup_uma_clk;
- uint32_t bootup_sclk;
- uint32_t dentist_vco_freq;
- uint32_t nb_dpm_enable;
- uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORY_CLOCK];
- uint32_t nbp_n_clock[CZ_NUM_NBPSTATES];
- uint8_t nbp_voltage_index[CZ_NUM_NBPSTATES];
- uint32_t display_clock[CZ_MAX_DISPLAY_CLOCK_LEVEL];
- uint16_t bootup_nb_voltage_index;
- uint8_t htc_tmp_lmt;
- uint8_t htc_hyst_lmt;
- uint32_t uma_channel_number;
-};
-
-struct cz_power_info {
- uint32_t active_target[CZ_MAX_HARDWARE_POWERLEVELS];
- struct cz_sys_info sys_info;
- struct cz_pl boot_pl;
- bool disable_nb_ps3_in_battery;
- bool battery_state;
- uint32_t lowest_valid;
- uint32_t highest_valid;
- uint16_t high_voltage_threshold;
- /* smc offsets */
- uint32_t sram_end;
- uint32_t dpm_table_start;
- uint32_t soft_regs_start;
- /* dpm SMU tables */
- uint8_t uvd_level_count;
- uint8_t vce_level_count;
- uint8_t acp_level_count;
- uint32_t fps_high_threshold;
- uint32_t fps_low_threshold;
- /* dpm table */
- uint32_t dpm_flags;
- struct cz_dpm_entry sclk_dpm;
- struct cz_dpm_entry uvd_dpm;
- struct cz_dpm_entry vce_dpm;
- struct cz_dpm_entry acp_dpm;
-
- uint8_t uvd_boot_level;
- uint8_t uvd_interval;
- uint8_t vce_boot_level;
- uint8_t vce_interval;
- uint8_t acp_boot_level;
- uint8_t acp_interval;
-
- uint8_t graphics_boot_level;
- uint8_t graphics_interval;
- uint8_t graphics_therm_throttle_enable;
- uint8_t graphics_voltage_change_enable;
- uint8_t graphics_clk_slow_enable;
- uint8_t graphics_clk_slow_divider;
-
- uint32_t low_sclk_interrupt_threshold;
- bool uvd_power_gated;
- bool vce_power_gated;
- bool acp_power_gated;
-
- uint32_t active_process_mask;
-
- uint32_t mgcg_cgtt_local0;
- uint32_t mgcg_cgtt_local1;
- uint32_t clock_slow_down_step;
- uint32_t skip_clock_slow_down;
- bool enable_nb_ps_policy;
- uint32_t voting_clients;
- uint32_t voltage_drop_threshold;
- uint32_t gfx_pg_threshold;
- uint32_t max_sclk_level;
- uint32_t max_uvd_level;
- uint32_t max_vce_level;
- /* flags */
- bool didt_enabled;
- bool video_start;
- bool cac_enabled;
- bool bapm_enabled;
- bool nb_dpm_enabled_by_driver;
- bool nb_dpm_enabled;
- bool auto_thermal_throttling_enabled;
- bool dpm_enabled;
- bool need_pptable_upload;
- /* caps */
- bool caps_cac;
- bool caps_power_containment;
- bool caps_sq_ramping;
- bool caps_db_ramping;
- bool caps_td_ramping;
- bool caps_tcp_ramping;
- bool caps_sclk_throttle_low_notification;
- bool caps_fps;
- bool caps_uvd_dpm;
- bool caps_uvd_pg;
- bool caps_vce_dpm;
- bool caps_vce_pg;
- bool caps_acp_dpm;
- bool caps_acp_pg;
- bool caps_stable_power_state;
- bool caps_enable_dfs_bypass;
- bool caps_sclk_ds;
- bool caps_voltage_island;
- /* power state */
- struct amdgpu_ps current_rps;
- struct cz_ps current_ps;
- struct amdgpu_ps requested_rps;
- struct cz_ps requested_ps;
-
- bool uvd_power_down;
- bool vce_power_down;
- bool acp_power_down;
-
- bool uvd_dynamic_pg;
-};
-
-/* cz_smc.c */
-uint32_t cz_get_argument(struct amdgpu_device *adev);
-int cz_send_msg_to_smc(struct amdgpu_device *adev, uint16_t msg);
-int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
- uint16_t msg, uint32_t parameter);
-int cz_read_smc_sram_dword(struct amdgpu_device *adev,
- uint32_t smc_address, uint32_t *value, uint32_t limit);
-int cz_smu_upload_pptable(struct amdgpu_device *adev);
-int cz_smu_download_pptable(struct amdgpu_device *adev, void **table);
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_smc.c b/drivers/gpu/drm/amd/amdgpu/cz_smc.c
deleted file mode 100644
index aed7033c0973..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/cz_smc.c
+++ /dev/null
@@ -1,995 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-#include <linux/firmware.h>
-#include "drmP.h"
-#include "amdgpu.h"
-#include "smu8.h"
-#include "smu8_fusion.h"
-#include "cz_ppsmc.h"
-#include "cz_smumgr.h"
-#include "smu_ucode_xfer_cz.h"
-#include "amdgpu_ucode.h"
-#include "cz_dpm.h"
-#include "vi_dpm.h"
-
-#include "smu/smu_8_0_d.h"
-#include "smu/smu_8_0_sh_mask.h"
-#include "gca/gfx_8_0_d.h"
-#include "gca/gfx_8_0_sh_mask.h"
-
-uint32_t cz_get_argument(struct amdgpu_device *adev)
-{
- return RREG32(mmSMU_MP1_SRBM2P_ARG_0);
-}
-
-static struct cz_smu_private_data *cz_smu_get_priv(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv =
- (struct cz_smu_private_data *)(adev->smu.priv);
-
- return priv;
-}
-
-static int cz_send_msg_to_smc_async(struct amdgpu_device *adev, u16 msg)
-{
- int i;
- u32 content = 0, tmp;
-
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = REG_GET_FIELD(RREG32(mmSMU_MP1_SRBM2P_RESP_0),
- SMU_MP1_SRBM2P_RESP_0, CONTENT);
- if (content != tmp)
- break;
- udelay(1);
- }
-
- /* timeout means wrong logic*/
- if (i == adev->usec_timeout)
- return -EINVAL;
-
- WREG32(mmSMU_MP1_SRBM2P_RESP_0, 0);
- WREG32(mmSMU_MP1_SRBM2P_MSG_0, msg);
-
- return 0;
-}
-
-int cz_send_msg_to_smc(struct amdgpu_device *adev, u16 msg)
-{
- int i;
- u32 content = 0, tmp = 0;
-
- if (cz_send_msg_to_smc_async(adev, msg))
- return -EINVAL;
-
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = REG_GET_FIELD(RREG32(mmSMU_MP1_SRBM2P_RESP_0),
- SMU_MP1_SRBM2P_RESP_0, CONTENT);
- if (content != tmp)
- break;
- udelay(1);
- }
-
- /* timeout means wrong logic*/
- if (i == adev->usec_timeout)
- return -EINVAL;
-
- if (PPSMC_Result_OK != tmp) {
- dev_err(adev->dev, "SMC Failed to send Message.\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
- u16 msg, u32 parameter)
-{
- WREG32(mmSMU_MP1_SRBM2P_ARG_0, parameter);
- return cz_send_msg_to_smc(adev, msg);
-}
-
-static int cz_set_smc_sram_address(struct amdgpu_device *adev,
- u32 smc_address, u32 limit)
-{
- if (smc_address & 3)
- return -EINVAL;
- if ((smc_address + 3) > limit)
- return -EINVAL;
-
- WREG32(mmMP0PUB_IND_INDEX_0, SMN_MP1_SRAM_START_ADDR + smc_address);
-
- return 0;
-}
-
-int cz_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
- u32 *value, u32 limit)
-{
- int ret;
-
- ret = cz_set_smc_sram_address(adev, smc_address, limit);
- if (ret)
- return ret;
-
- *value = RREG32(mmMP0PUB_IND_DATA_0);
-
- return 0;
-}
-
-static int cz_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
- u32 value, u32 limit)
-{
- int ret;
-
- ret = cz_set_smc_sram_address(adev, smc_address, limit);
- if (ret)
- return ret;
-
- WREG32(mmMP0PUB_IND_DATA_0, value);
-
- return 0;
-}
-
-static int cz_smu_request_load_fw(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- uint32_t smc_addr = SMU8_FIRMWARE_HEADER_LOCATION +
- offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
-
- cz_write_smc_sram_dword(adev, smc_addr, 0, smc_addr + 4);
-
- /*prepare toc buffers*/
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_DriverDramAddrHi,
- priv->toc_buffer.mc_addr_high);
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_DriverDramAddrLo,
- priv->toc_buffer.mc_addr_low);
- cz_send_msg_to_smc(adev, PPSMC_MSG_InitJobs);
-
- /*execute jobs*/
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ExecuteJob,
- priv->toc_entry_aram);
-
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ExecuteJob,
- priv->toc_entry_power_profiling_index);
-
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ExecuteJob,
- priv->toc_entry_initialize_index);
-
- return 0;
-}
-
-/*
- *Check if the FW has been loaded, SMU will not return if loading
- *has not finished.
- */
-static int cz_smu_check_fw_load_finish(struct amdgpu_device *adev,
- uint32_t fw_mask)
-{
- int i;
- uint32_t index = SMN_MP1_SRAM_START_ADDR +
- SMU8_FIRMWARE_HEADER_LOCATION +
- offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
-
- WREG32(mmMP0PUB_IND_INDEX, index);
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if (fw_mask == (RREG32(mmMP0PUB_IND_DATA) & fw_mask))
- break;
- udelay(1);
- }
-
- if (i >= adev->usec_timeout) {
- dev_err(adev->dev,
- "SMU check loaded firmware failed, expecting 0x%x, getting 0x%x",
- fw_mask, RREG32(mmMP0PUB_IND_DATA));
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * interfaces for different ip blocks to check firmware loading status
- * 0 for success otherwise failed
- */
-static int cz_smu_check_finished(struct amdgpu_device *adev,
- enum AMDGPU_UCODE_ID id)
-{
- switch (id) {
- case AMDGPU_UCODE_ID_SDMA0:
- if (adev->smu.fw_flags & AMDGPU_SDMA0_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_SDMA1:
- if (adev->smu.fw_flags & AMDGPU_SDMA1_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_CP_CE:
- if (adev->smu.fw_flags & AMDGPU_CPCE_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_CP_PFP:
- if (adev->smu.fw_flags & AMDGPU_CPPFP_UCODE_LOADED)
- return 0;
- case AMDGPU_UCODE_ID_CP_ME:
- if (adev->smu.fw_flags & AMDGPU_CPME_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_CP_MEC1:
- if (adev->smu.fw_flags & AMDGPU_CPMEC1_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_CP_MEC2:
- if (adev->smu.fw_flags & AMDGPU_CPMEC2_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_RLC_G:
- if (adev->smu.fw_flags & AMDGPU_CPRLC_UCODE_LOADED)
- return 0;
- break;
- case AMDGPU_UCODE_ID_MAXIMUM:
- default:
- break;
- }
-
- return 1;
-}
-
-static int cz_load_mec_firmware(struct amdgpu_device *adev)
-{
- struct amdgpu_firmware_info *ucode =
- &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1];
- uint32_t reg_data;
- uint32_t tmp;
-
- if (ucode->fw == NULL)
- return -EINVAL;
-
- /* Disable MEC parsing/prefetching */
- tmp = RREG32(mmCP_MEC_CNTL);
- tmp = REG_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
- tmp = REG_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
- WREG32(mmCP_MEC_CNTL, tmp);
-
- tmp = RREG32(mmCP_CPC_IC_BASE_CNTL);
- tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
- tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
- tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
- tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
- WREG32(mmCP_CPC_IC_BASE_CNTL, tmp);
-
- reg_data = lower_32_bits(ucode->mc_addr) &
- REG_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
- WREG32(mmCP_CPC_IC_BASE_LO, reg_data);
-
- reg_data = upper_32_bits(ucode->mc_addr) &
- REG_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
- WREG32(mmCP_CPC_IC_BASE_HI, reg_data);
-
- return 0;
-}
-
-int cz_smu_start(struct amdgpu_device *adev)
-{
- int ret = 0;
-
- uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
- UCODE_ID_SDMA0_MASK |
- UCODE_ID_SDMA1_MASK |
- UCODE_ID_CP_CE_MASK |
- UCODE_ID_CP_ME_MASK |
- UCODE_ID_CP_PFP_MASK |
- UCODE_ID_CP_MEC_JT1_MASK |
- UCODE_ID_CP_MEC_JT2_MASK;
-
- if (adev->asic_type == CHIP_STONEY)
- fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
-
- cz_smu_request_load_fw(adev);
- ret = cz_smu_check_fw_load_finish(adev, fw_to_check);
- if (ret)
- return ret;
-
- /* manually load MEC firmware for CZ */
- if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY) {
- ret = cz_load_mec_firmware(adev);
- if (ret) {
- dev_err(adev->dev, "(%d) Mec Firmware load failed\n", ret);
- return ret;
- }
- }
-
- /* setup fw load flag */
- adev->smu.fw_flags = AMDGPU_SDMA0_UCODE_LOADED |
- AMDGPU_SDMA1_UCODE_LOADED |
- AMDGPU_CPCE_UCODE_LOADED |
- AMDGPU_CPPFP_UCODE_LOADED |
- AMDGPU_CPME_UCODE_LOADED |
- AMDGPU_CPMEC1_UCODE_LOADED |
- AMDGPU_CPMEC2_UCODE_LOADED |
- AMDGPU_CPRLC_UCODE_LOADED;
-
- if (adev->asic_type == CHIP_STONEY)
- adev->smu.fw_flags &= ~(AMDGPU_SDMA1_UCODE_LOADED | AMDGPU_CPMEC2_UCODE_LOADED);
-
- return ret;
-}
-
-static uint32_t cz_convert_fw_type(uint32_t fw_type)
-{
- enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM;
-
- switch (fw_type) {
- case UCODE_ID_SDMA0:
- result = AMDGPU_UCODE_ID_SDMA0;
- break;
- case UCODE_ID_SDMA1:
- result = AMDGPU_UCODE_ID_SDMA1;
- break;
- case UCODE_ID_CP_CE:
- result = AMDGPU_UCODE_ID_CP_CE;
- break;
- case UCODE_ID_CP_PFP:
- result = AMDGPU_UCODE_ID_CP_PFP;
- break;
- case UCODE_ID_CP_ME:
- result = AMDGPU_UCODE_ID_CP_ME;
- break;
- case UCODE_ID_CP_MEC_JT1:
- case UCODE_ID_CP_MEC_JT2:
- result = AMDGPU_UCODE_ID_CP_MEC1;
- break;
- case UCODE_ID_RLC_G:
- result = AMDGPU_UCODE_ID_RLC_G;
- break;
- default:
- DRM_ERROR("UCode type is out of range!");
- }
-
- return result;
-}
-
-static uint8_t cz_smu_translate_firmware_enum_to_arg(
- enum cz_scratch_entry firmware_enum)
-{
- uint8_t ret = 0;
-
- switch (firmware_enum) {
- case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0:
- ret = UCODE_ID_SDMA0;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1:
- ret = UCODE_ID_SDMA1;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE:
- ret = UCODE_ID_CP_CE;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP:
- ret = UCODE_ID_CP_PFP;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME:
- ret = UCODE_ID_CP_ME;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1:
- ret = UCODE_ID_CP_MEC_JT1;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2:
- ret = UCODE_ID_CP_MEC_JT2;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG:
- ret = UCODE_ID_GMCON_RENG;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G:
- ret = UCODE_ID_RLC_G;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH:
- ret = UCODE_ID_RLC_SCRATCH;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM:
- ret = UCODE_ID_RLC_SRM_ARAM;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM:
- ret = UCODE_ID_RLC_SRM_DRAM;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM:
- ret = UCODE_ID_DMCU_ERAM;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM:
- ret = UCODE_ID_DMCU_IRAM;
- break;
- case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING:
- ret = TASK_ARG_INIT_MM_PWR_LOG;
- break;
- case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT:
- case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING:
- case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS:
- case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT:
- case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START:
- case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS:
- ret = TASK_ARG_REG_MMIO;
- break;
- case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE:
- ret = TASK_ARG_INIT_CLK_TABLE;
- break;
- }
-
- return ret;
-}
-
-static int cz_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
- enum cz_scratch_entry firmware_enum,
- struct cz_buffer_entry *entry)
-{
- uint64_t gpu_addr;
- uint32_t data_size;
- uint8_t ucode_id = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
- enum AMDGPU_UCODE_ID id = cz_convert_fw_type(ucode_id);
- struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
- const struct gfx_firmware_header_v1_0 *header;
-
- if (ucode->fw == NULL)
- return -EINVAL;
-
- gpu_addr = ucode->mc_addr;
- header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
- data_size = le32_to_cpu(header->header.ucode_size_bytes);
-
- if ((firmware_enum == CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1) ||
- (firmware_enum == CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2)) {
- gpu_addr += le32_to_cpu(header->jt_offset) << 2;
- data_size = le32_to_cpu(header->jt_size) << 2;
- }
-
- entry->mc_addr_low = lower_32_bits(gpu_addr);
- entry->mc_addr_high = upper_32_bits(gpu_addr);
- entry->data_size = data_size;
- entry->firmware_ID = firmware_enum;
-
- return 0;
-}
-
-static int cz_smu_populate_single_scratch_entry(struct amdgpu_device *adev,
- enum cz_scratch_entry scratch_type,
- uint32_t size_in_byte,
- struct cz_buffer_entry *entry)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- uint64_t mc_addr = (((uint64_t) priv->smu_buffer.mc_addr_high) << 32) |
- priv->smu_buffer.mc_addr_low;
- mc_addr += size_in_byte;
-
- priv->smu_buffer_used_bytes += size_in_byte;
- entry->data_size = size_in_byte;
- entry->kaddr = priv->smu_buffer.kaddr + priv->smu_buffer_used_bytes;
- entry->mc_addr_low = lower_32_bits(mc_addr);
- entry->mc_addr_high = upper_32_bits(mc_addr);
- entry->firmware_ID = scratch_type;
-
- return 0;
-}
-
-static int cz_smu_populate_single_ucode_load_task(struct amdgpu_device *adev,
- enum cz_scratch_entry firmware_enum,
- bool is_last)
-{
- uint8_t i;
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
- struct SMU_Task *task = &toc->tasks[priv->toc_entry_used_count++];
-
- task->type = TASK_TYPE_UCODE_LOAD;
- task->arg = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
- task->next = is_last ? END_OF_TASK_LIST : priv->toc_entry_used_count;
-
- for (i = 0; i < priv->driver_buffer_length; i++)
- if (priv->driver_buffer[i].firmware_ID == firmware_enum)
- break;
-
- if (i >= priv->driver_buffer_length) {
- dev_err(adev->dev, "Invalid Firmware Type\n");
- return -EINVAL;
- }
-
- task->addr.low = priv->driver_buffer[i].mc_addr_low;
- task->addr.high = priv->driver_buffer[i].mc_addr_high;
- task->size_bytes = priv->driver_buffer[i].data_size;
-
- return 0;
-}
-
-static int cz_smu_populate_single_scratch_task(struct amdgpu_device *adev,
- enum cz_scratch_entry firmware_enum,
- uint8_t type, bool is_last)
-{
- uint8_t i;
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
- struct SMU_Task *task = &toc->tasks[priv->toc_entry_used_count++];
-
- task->type = type;
- task->arg = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
- task->next = is_last ? END_OF_TASK_LIST : priv->toc_entry_used_count;
-
- for (i = 0; i < priv->scratch_buffer_length; i++)
- if (priv->scratch_buffer[i].firmware_ID == firmware_enum)
- break;
-
- if (i >= priv->scratch_buffer_length) {
- dev_err(adev->dev, "Invalid Firmware Type\n");
- return -EINVAL;
- }
-
- task->addr.low = priv->scratch_buffer[i].mc_addr_low;
- task->addr.high = priv->scratch_buffer[i].mc_addr_high;
- task->size_bytes = priv->scratch_buffer[i].data_size;
-
- if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == firmware_enum) {
- struct cz_ih_meta_data *pIHReg_restore =
- (struct cz_ih_meta_data *)priv->scratch_buffer[i].kaddr;
- pIHReg_restore->command =
- METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
- }
-
- return 0;
-}
-
-static int cz_smu_construct_toc_for_rlc_aram_save(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- priv->toc_entry_aram = priv->toc_entry_used_count;
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
- TASK_TYPE_UCODE_SAVE, true);
-
- return 0;
-}
-
-static int cz_smu_construct_toc_for_vddgfx_enter(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
-
- toc->JobList[JOB_GFX_SAVE] = (uint8_t)priv->toc_entry_used_count;
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
- TASK_TYPE_UCODE_SAVE, false);
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
- TASK_TYPE_UCODE_SAVE, true);
-
- return 0;
-}
-
-static int cz_smu_construct_toc_for_vddgfx_exit(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
-
- toc->JobList[JOB_GFX_RESTORE] = (uint8_t)priv->toc_entry_used_count;
-
- /* populate ucode */
- if (adev->firmware.smu_load) {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
- if (adev->asic_type == CHIP_STONEY) {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
- } else {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
- }
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
- }
-
- /* populate scratch */
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
- TASK_TYPE_UCODE_LOAD, false);
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
- TASK_TYPE_UCODE_LOAD, false);
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
- TASK_TYPE_UCODE_LOAD, true);
-
- return 0;
-}
-
-static int cz_smu_construct_toc_for_power_profiling(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- priv->toc_entry_power_profiling_index = priv->toc_entry_used_count;
-
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
- TASK_TYPE_INITIALIZE, true);
- return 0;
-}
-
-static int cz_smu_construct_toc_for_bootup(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- priv->toc_entry_initialize_index = priv->toc_entry_used_count;
-
- if (adev->firmware.smu_load) {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
- if (adev->asic_type == CHIP_STONEY) {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
- } else {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
- }
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
- if (adev->asic_type == CHIP_STONEY) {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
- } else {
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
- }
- cz_smu_populate_single_ucode_load_task(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
- }
-
- return 0;
-}
-
-static int cz_smu_construct_toc_for_clock_table(struct amdgpu_device *adev)
-{
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- priv->toc_entry_clock_table = priv->toc_entry_used_count;
-
- cz_smu_populate_single_scratch_task(adev,
- CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
- TASK_TYPE_INITIALIZE, true);
-
- return 0;
-}
-
-static int cz_smu_initialize_toc_empty_job_list(struct amdgpu_device *adev)
-{
- int i;
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
- struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
-
- for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
- toc->JobList[i] = (uint8_t)IGNORE_JOB;
-
- return 0;
-}
-
-/*
- * cz smu uninitialization
- */
-int cz_smu_fini(struct amdgpu_device *adev)
-{
- amdgpu_bo_unref(&adev->smu.toc_buf);
- amdgpu_bo_unref(&adev->smu.smu_buf);
- kfree(adev->smu.priv);
- adev->smu.priv = NULL;
- if (adev->firmware.smu_load)
- amdgpu_ucode_fini_bo(adev);
-
- return 0;
-}
-
-int cz_smu_download_pptable(struct amdgpu_device *adev, void **table)
-{
- uint8_t i;
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- for (i = 0; i < priv->scratch_buffer_length; i++)
- if (priv->scratch_buffer[i].firmware_ID ==
- CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
- break;
-
- if (i >= priv->scratch_buffer_length) {
- dev_err(adev->dev, "Invalid Scratch Type\n");
- return -EINVAL;
- }
-
- *table = (struct SMU8_Fusion_ClkTable *)priv->scratch_buffer[i].kaddr;
-
- /* prepare buffer for pptable */
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetClkTableAddrHi,
- priv->scratch_buffer[i].mc_addr_high);
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetClkTableAddrLo,
- priv->scratch_buffer[i].mc_addr_low);
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ExecuteJob,
- priv->toc_entry_clock_table);
-
- /* actual downloading */
- cz_send_msg_to_smc(adev, PPSMC_MSG_ClkTableXferToDram);
-
- return 0;
-}
-
-int cz_smu_upload_pptable(struct amdgpu_device *adev)
-{
- uint8_t i;
- struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
-
- for (i = 0; i < priv->scratch_buffer_length; i++)
- if (priv->scratch_buffer[i].firmware_ID ==
- CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
- break;
-
- if (i >= priv->scratch_buffer_length) {
- dev_err(adev->dev, "Invalid Scratch Type\n");
- return -EINVAL;
- }
-
- /* prepare SMU */
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetClkTableAddrHi,
- priv->scratch_buffer[i].mc_addr_high);
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_SetClkTableAddrLo,
- priv->scratch_buffer[i].mc_addr_low);
- cz_send_msg_to_smc_with_parameter(adev,
- PPSMC_MSG_ExecuteJob,
- priv->toc_entry_clock_table);
-
- /* actual uploading */
- cz_send_msg_to_smc(adev, PPSMC_MSG_ClkTableXferToSmu);
-
- return 0;
-}
-
-/*
- * cz smumgr functions initialization
- */
-static const struct amdgpu_smumgr_funcs cz_smumgr_funcs = {
- .check_fw_load_finish = cz_smu_check_finished,
- .request_smu_load_fw = NULL,
- .request_smu_specific_fw = NULL,
-};
-
-/*
- * cz smu initialization
- */
-int cz_smu_init(struct amdgpu_device *adev)
-{
- int ret = -EINVAL;
- uint64_t mc_addr = 0;
- struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
- struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
- void *toc_buf_ptr = NULL;
- void *smu_buf_ptr = NULL;
-
- struct cz_smu_private_data *priv =
- kzalloc(sizeof(struct cz_smu_private_data), GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
-
- /* allocate firmware buffers */
- if (adev->firmware.smu_load)
- amdgpu_ucode_init_bo(adev);
-
- adev->smu.priv = priv;
- adev->smu.fw_flags = 0;
- priv->toc_buffer.data_size = 4096;
-
- priv->smu_buffer.data_size =
- ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) +
- ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) +
- ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) +
- ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) +
- ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32);
-
- /* prepare toc buffer and smu buffer:
- * 1. create amdgpu_bo for toc buffer and smu buffer
- * 2. pin mc address
- * 3. map kernel virtual address
- */
- ret = amdgpu_bo_create(adev, priv->toc_buffer.data_size, PAGE_SIZE,
- true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL,
- toc_buf);
-
- if (ret) {
- dev_err(adev->dev, "(%d) SMC TOC buffer allocation failed\n", ret);
- return ret;
- }
-
- ret = amdgpu_bo_create(adev, priv->smu_buffer.data_size, PAGE_SIZE,
- true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL,
- smu_buf);
-
- if (ret) {
- dev_err(adev->dev, "(%d) SMC Internal buffer allocation failed\n", ret);
- return ret;
- }
-
- /* toc buffer reserve/pin/map */
- ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
- if (ret) {
- amdgpu_bo_unref(&adev->smu.toc_buf);
- dev_err(adev->dev, "(%d) SMC TOC buffer reserve failed\n", ret);
- return ret;
- }
-
- ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_GTT, &mc_addr);
- if (ret) {
- amdgpu_bo_unreserve(adev->smu.toc_buf);
- amdgpu_bo_unref(&adev->smu.toc_buf);
- dev_err(adev->dev, "(%d) SMC TOC buffer pin failed\n", ret);
- return ret;
- }
-
- ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
- if (ret)
- goto smu_init_failed;
-
- amdgpu_bo_unreserve(adev->smu.toc_buf);
-
- priv->toc_buffer.mc_addr_low = lower_32_bits(mc_addr);
- priv->toc_buffer.mc_addr_high = upper_32_bits(mc_addr);
- priv->toc_buffer.kaddr = toc_buf_ptr;
-
- /* smu buffer reserve/pin/map */
- ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
- if (ret) {
- amdgpu_bo_unref(&adev->smu.smu_buf);
- dev_err(adev->dev, "(%d) SMC Internal buffer reserve failed\n", ret);
- return ret;
- }
-
- ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_GTT, &mc_addr);
- if (ret) {
- amdgpu_bo_unreserve(adev->smu.smu_buf);
- amdgpu_bo_unref(&adev->smu.smu_buf);
- dev_err(adev->dev, "(%d) SMC Internal buffer pin failed\n", ret);
- return ret;
- }
-
- ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
- if (ret)
- goto smu_init_failed;
-
- amdgpu_bo_unreserve(adev->smu.smu_buf);
-
- priv->smu_buffer.mc_addr_low = lower_32_bits(mc_addr);
- priv->smu_buffer.mc_addr_high = upper_32_bits(mc_addr);
- priv->smu_buffer.kaddr = smu_buf_ptr;
-
- if (adev->firmware.smu_load) {
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
-
- if (adev->asic_type == CHIP_STONEY) {
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- } else {
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- }
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- if (adev->asic_type == CHIP_STONEY) {
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- } else {
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- }
- if (cz_smu_populate_single_firmware_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
- &priv->driver_buffer[priv->driver_buffer_length++]))
- goto smu_init_failed;
- }
-
- if (cz_smu_populate_single_scratch_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
- UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
- &priv->scratch_buffer[priv->scratch_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_scratch_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
- UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
- &priv->scratch_buffer[priv->scratch_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_scratch_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
- UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
- &priv->scratch_buffer[priv->scratch_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_scratch_entry(adev,
- CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
- sizeof(struct SMU8_MultimediaPowerLogData),
- &priv->scratch_buffer[priv->scratch_buffer_length++]))
- goto smu_init_failed;
- if (cz_smu_populate_single_scratch_entry(adev,
- CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
- sizeof(struct SMU8_Fusion_ClkTable),
- &priv->scratch_buffer[priv->scratch_buffer_length++]))
- goto smu_init_failed;
-
- cz_smu_initialize_toc_empty_job_list(adev);
- cz_smu_construct_toc_for_rlc_aram_save(adev);
- cz_smu_construct_toc_for_vddgfx_enter(adev);
- cz_smu_construct_toc_for_vddgfx_exit(adev);
- cz_smu_construct_toc_for_power_profiling(adev);
- cz_smu_construct_toc_for_bootup(adev);
- cz_smu_construct_toc_for_clock_table(adev);
- /* init the smumgr functions */
- adev->smu.smumgr_funcs = &cz_smumgr_funcs;
-
- return 0;
-
-smu_init_failed:
- amdgpu_bo_unref(toc_buf);
- amdgpu_bo_unref(smu_buf);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h b/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h
deleted file mode 100644
index 026342fcf0f3..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-#ifndef __CZ_SMC_H__
-#define __CZ_SMC_H__
-
-#define MAX_NUM_FIRMWARE 8
-#define MAX_NUM_SCRATCH 11
-#define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024
-#define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048
-#define CZ_SCRATCH_SIZE_SDMA_METADATA 1024
-#define CZ_SCRATCH_SIZE_IH ((2*256+1)*4)
-
-enum cz_scratch_entry {
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0,
- CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
- CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
- CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
- CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
- CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM,
- CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM,
- CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
- CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT,
- CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING,
- CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS,
- CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT,
- CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START,
- CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS,
- CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE
-};
-
-struct cz_buffer_entry {
- uint32_t data_size;
- uint32_t mc_addr_low;
- uint32_t mc_addr_high;
- void *kaddr;
- enum cz_scratch_entry firmware_ID;
-};
-
-struct cz_register_index_data_pair {
- uint32_t offset;
- uint32_t value;
-};
-
-struct cz_ih_meta_data {
- uint32_t command;
- struct cz_register_index_data_pair register_index_value_pair[1];
-};
-
-struct cz_smu_private_data {
- uint8_t driver_buffer_length;
- uint8_t scratch_buffer_length;
- uint16_t toc_entry_used_count;
- uint16_t toc_entry_initialize_index;
- uint16_t toc_entry_power_profiling_index;
- uint16_t toc_entry_aram;
- uint16_t toc_entry_ih_register_restore_task_index;
- uint16_t toc_entry_clock_table;
- uint16_t ih_register_restore_task_size;
- uint16_t smu_buffer_used_bytes;
-
- struct cz_buffer_entry toc_buffer;
- struct cz_buffer_entry smu_buffer;
- struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE];
- struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH];
-};
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 84afaae97e65..d4452d8f76ca 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -2512,6 +2512,8 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
@@ -2537,7 +2539,6 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
@@ -2578,7 +2579,9 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v10_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
@@ -2587,16 +2590,10 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v10_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v10_0_show_cursor(crtc);
@@ -2620,7 +2617,6 @@ unpin:
static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v10_0_lock_cursor(crtc, true);
@@ -2628,10 +2624,6 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v10_0_show_cursor(crtc);
dce_v10_0_lock_cursor(crtc, false);
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 7a7fa96d2e49..1cf1d9d1aec1 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -167,6 +167,7 @@ static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev)
(const u32)ARRAY_SIZE(stoney_golden_settings_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
polaris11_golden_settings_a11,
(const u32)ARRAY_SIZE(polaris11_golden_settings_a11));
@@ -608,6 +609,7 @@ static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev)
num_crtc = 6;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
num_crtc = 5;
break;
default:
@@ -1589,6 +1591,7 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev)
adev->mode_info.audio.num_pins = 8;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
adev->mode_info.audio.num_pins = 6;
break;
default:
@@ -2388,7 +2391,8 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc)
int pll;
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
struct amdgpu_encoder *amdgpu_encoder =
to_amdgpu_encoder(amdgpu_crtc->encoder);
struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
@@ -2528,6 +2532,8 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
@@ -2553,7 +2559,6 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
@@ -2594,7 +2599,9 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v11_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
@@ -2603,16 +2610,10 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v11_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v11_0_show_cursor(crtc);
@@ -2636,7 +2637,6 @@ unpin:
static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v11_0_lock_cursor(crtc, true);
@@ -2644,10 +2644,6 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v11_0_show_cursor(crtc);
dce_v11_0_lock_cursor(crtc, false);
@@ -2822,7 +2818,8 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc,
return -EINVAL;
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
struct amdgpu_encoder *amdgpu_encoder =
to_amdgpu_encoder(amdgpu_crtc->encoder);
int encoder_mode =
@@ -2992,6 +2989,7 @@ static int dce_v11_0_early_init(void *handle)
adev->mode_info.num_dig = 6;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
adev->mode_info.num_hpd = 5;
adev->mode_info.num_dig = 5;
break;
@@ -3101,7 +3099,8 @@ static int dce_v11_0_hw_init(void *handle)
amdgpu_atombios_crtc_powergate_init(adev);
amdgpu_atombios_encoder_init_dig(adev);
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk,
DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS);
amdgpu_atombios_crtc_set_dce_clock(adev, 0,
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index 44f024c9b9aa..809aa94a0cc1 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -1859,6 +1859,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
+ int w = amdgpu_crtc->cursor_width;
+
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
@@ -1878,6 +1880,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
@@ -1903,7 +1907,6 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
@@ -1944,7 +1947,9 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v6_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
@@ -1953,16 +1958,10 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v6_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v6_0_show_cursor(crtc);
@@ -1986,7 +1985,6 @@ unpin:
static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v6_0_lock_cursor(crtc, true);
@@ -1994,10 +1992,6 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v6_0_show_cursor(crtc);
dce_v6_0_lock_cursor(crtc, false);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 30945fe55ac7..d2590d75aa11 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -2363,6 +2363,8 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc,
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
@@ -2388,7 +2390,6 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
@@ -2429,7 +2430,9 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v8_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
@@ -2438,16 +2441,10 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
dce_v8_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v8_0_show_cursor(crtc);
@@ -2471,7 +2468,6 @@ unpin:
static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v8_0_lock_cursor(crtc, true);
@@ -2479,10 +2475,6 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v8_0_show_cursor(crtc);
dce_v8_0_lock_cursor(crtc, false);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index b323f5ef64d2..c998f6aaaf36 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -25,7 +25,7 @@
#include "amdgpu_ih.h"
#include "amdgpu_gfx.h"
#include "amdgpu_ucode.h"
-#include "si/clearstate_si.h"
+#include "clearstate_si.h"
#include "bif/bif_3_0_d.h"
#include "bif/bif_3_0_sh_mask.h"
#include "oss/oss_1_0_d.h"
@@ -1794,14 +1794,9 @@ static void gfx_v6_0_gpu_init(struct amdgpu_device *adev)
static void gfx_v6_0_scratch_init(struct amdgpu_device *adev)
{
- int i;
-
adev->gfx.scratch.num_reg = 7;
adev->gfx.scratch.reg_base = mmSCRATCH_REG0;
- for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
- adev->gfx.scratch.free[i] = true;
- adev->gfx.scratch.reg[i] = adev->gfx.scratch.reg_base + i;
- }
+ adev->gfx.scratch.free_mask = (1u << adev->gfx.scratch.num_reg) - 1;
}
static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
@@ -1975,7 +1970,7 @@ static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[2] = 0xDEADBEEF;
ib.length_dw = 3;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err2;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index c4e14015ec5b..e3589b55a1e1 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -2003,14 +2003,9 @@ static void gfx_v7_0_gpu_init(struct amdgpu_device *adev)
*/
static void gfx_v7_0_scratch_init(struct amdgpu_device *adev)
{
- int i;
-
adev->gfx.scratch.num_reg = 7;
adev->gfx.scratch.reg_base = mmSCRATCH_REG0;
- for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
- adev->gfx.scratch.free[i] = true;
- adev->gfx.scratch.reg[i] = adev->gfx.scratch.reg_base + i;
- }
+ adev->gfx.scratch.free_mask = (1u << adev->gfx.scratch.num_reg) - 1;
}
/**
@@ -2321,7 +2316,7 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[2] = 0xDEADBEEF;
ib.length_dw = 3;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err2;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index d0ec00986f38..35f9cd83b821 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -139,6 +139,13 @@ MODULE_FIRMWARE("amdgpu/polaris10_mec.bin");
MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin");
MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_ce.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_me.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin");
+
static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] =
{
{mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0},
@@ -650,6 +657,8 @@ static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev);
static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev);
static u32 gfx_v8_0_get_csb_size(struct amdgpu_device *adev);
static void gfx_v8_0_get_cu_info(struct amdgpu_device *adev);
+static void gfx_v8_0_ring_emit_ce_meta_init(struct amdgpu_ring *ring, uint64_t addr);
+static void gfx_v8_0_ring_emit_de_meta_init(struct amdgpu_ring *ring, uint64_t addr);
static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
{
@@ -689,6 +698,7 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
(const u32)ARRAY_SIZE(tonga_golden_common_all));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -741,14 +751,9 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
static void gfx_v8_0_scratch_init(struct amdgpu_device *adev)
{
- int i;
-
adev->gfx.scratch.num_reg = 7;
adev->gfx.scratch.reg_base = mmSCRATCH_REG0;
- for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
- adev->gfx.scratch.free[i] = true;
- adev->gfx.scratch.reg[i] = adev->gfx.scratch.reg_base + i;
- }
+ adev->gfx.scratch.free_mask = (1u << adev->gfx.scratch.num_reg) - 1;
}
static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
@@ -821,7 +826,7 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[2] = 0xDEADBEEF;
ib.length_dw = 3;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err2;
@@ -903,6 +908,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_STONEY:
chip_name = "stoney";
break;
@@ -930,6 +938,13 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+
+ /* chain ib ucode isn't formal released, just disable it by far
+ * TODO: when ucod ready we should use ucode version to judge if
+ * chain-ib support or not.
+ */
+ adev->virt.chained_ib_support = false;
+
adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
@@ -1356,6 +1371,51 @@ static void gfx_v8_0_mec_fini(struct amdgpu_device *adev)
}
}
+static int gfx_v8_0_kiq_init_ring(struct amdgpu_device *adev,
+ struct amdgpu_ring *ring,
+ struct amdgpu_irq_src *irq)
+{
+ int r = 0;
+
+ if (amdgpu_sriov_vf(adev)) {
+ r = amdgpu_wb_get(adev, &adev->virt.reg_val_offs);
+ if (r)
+ return r;
+ }
+
+ ring->adev = NULL;
+ ring->ring_obj = NULL;
+ ring->use_doorbell = true;
+ ring->doorbell_index = AMDGPU_DOORBELL_KIQ;
+ if (adev->gfx.mec2_fw) {
+ ring->me = 2;
+ ring->pipe = 0;
+ } else {
+ ring->me = 1;
+ ring->pipe = 1;
+ }
+
+ irq->data = ring;
+ ring->queue = 0;
+ sprintf(ring->name, "kiq %d.%d.%d", ring->me, ring->pipe, ring->queue);
+ r = amdgpu_ring_init(adev, ring, 1024,
+ irq, AMDGPU_CP_KIQ_IRQ_DRIVER0);
+ if (r)
+ dev_warn(adev->dev, "(%d) failed to init kiq ring\n", r);
+
+ return r;
+}
+
+static void gfx_v8_0_kiq_free_ring(struct amdgpu_ring *ring,
+ struct amdgpu_irq_src *irq)
+{
+ if (amdgpu_sriov_vf(ring->adev))
+ amdgpu_wb_free(ring->adev, ring->adev->virt.reg_val_offs);
+
+ amdgpu_ring_fini(ring);
+ irq->data = NULL;
+}
+
#define MEC_HPD_SIZE 2048
static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
@@ -1410,6 +1470,35 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
return 0;
}
+static void gfx_v8_0_kiq_fini(struct amdgpu_device *adev)
+{
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+
+ amdgpu_bo_free_kernel(&kiq->eop_obj, &kiq->eop_gpu_addr, NULL);
+ kiq->eop_obj = NULL;
+}
+
+static int gfx_v8_0_kiq_init(struct amdgpu_device *adev)
+{
+ int r;
+ u32 *hpd;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+
+ r = amdgpu_bo_create_kernel(adev, MEC_HPD_SIZE, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_GTT, &kiq->eop_obj,
+ &kiq->eop_gpu_addr, (void **)&hpd);
+ if (r) {
+ dev_warn(adev->dev, "failed to create KIQ bo (%d).\n", r);
+ return r;
+ }
+
+ memset(hpd, 0, MEC_HPD_SIZE);
+
+ amdgpu_bo_kunmap(kiq->eop_obj);
+
+ return 0;
+}
+
static const u32 vgpr_init_compute_shader[] =
{
0x7e000209, 0x7e020208,
@@ -1691,7 +1780,7 @@ static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
/* shedule the ib on the ring */
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r) {
DRM_ERROR("amdgpu: ib submit failed (%d).\n", r);
goto fail;
@@ -1768,6 +1857,7 @@ static int gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
ret = amdgpu_atombios_get_gfx_info(adev);
if (ret)
return ret;
@@ -1985,8 +2075,14 @@ static int gfx_v8_0_sw_init(void *handle)
{
int i, r;
struct amdgpu_ring *ring;
+ struct amdgpu_kiq *kiq;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ /* KIQ event */
+ r = amdgpu_irq_add_id(adev, 178, &adev->gfx.kiq.irq);
+ if (r)
+ return r;
+
/* EOP Event */
r = amdgpu_irq_add_id(adev, 181, &adev->gfx.eop_irq);
if (r)
@@ -2024,6 +2120,17 @@ static int gfx_v8_0_sw_init(void *handle)
return r;
}
+ r = gfx_v8_0_kiq_init(adev);
+ if (r) {
+ DRM_ERROR("Failed to init KIQ BOs!\n");
+ return r;
+ }
+
+ kiq = &adev->gfx.kiq;
+ r = gfx_v8_0_kiq_init_ring(adev, &kiq->ring, &kiq->irq);
+ if (r)
+ return r;
+
/* set up the gfx ring */
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
@@ -2107,7 +2214,9 @@ static int gfx_v8_0_sw_fini(void *handle)
amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
for (i = 0; i < adev->gfx.num_compute_rings; i++)
amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
+ gfx_v8_0_kiq_free_ring(&adev->gfx.kiq.ring, &adev->gfx.kiq.irq);
+ gfx_v8_0_kiq_fini(adev);
gfx_v8_0_mec_fini(adev);
gfx_v8_0_rlc_fini(adev);
gfx_v8_0_free_microcode(adev);
@@ -2682,6 +2791,7 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_16x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
@@ -3503,6 +3613,7 @@ gfx_v8_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
*rconf1 |= 0x0;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
*rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
SE_XSEL(1) | SE_YSEL(1);
*rconf1 |= 0x0;
@@ -4010,18 +4121,8 @@ static void gfx_v8_0_init_pg(struct amdgpu_device *adev)
WREG32(mmRLC_JUMP_TABLE_RESTORE, adev->gfx.rlc.cp_table_gpu_addr >> 8);
gfx_v8_0_init_power_gating(adev);
WREG32(mmRLC_PG_ALWAYS_ON_CU_MASK, adev->gfx.cu_info.ao_cu_mask);
- if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) {
- cz_enable_sck_slow_down_on_power_up(adev, true);
- cz_enable_sck_slow_down_on_power_down(adev, true);
- } else {
- cz_enable_sck_slow_down_on_power_up(adev, false);
- cz_enable_sck_slow_down_on_power_down(adev, false);
- }
- if (adev->pg_flags & AMD_PG_SUPPORT_CP)
- cz_enable_cp_power_gating(adev, true);
- else
- cz_enable_cp_power_gating(adev, false);
- } else if (adev->asic_type == CHIP_POLARIS11) {
+ } else if ((adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
gfx_v8_0_init_csb(adev);
gfx_v8_0_init_save_restore_list(adev);
gfx_v8_0_enable_save_restore_machine(adev);
@@ -4095,7 +4196,8 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
if (adev->asic_type == CHIP_POLARIS11 ||
- adev->asic_type == CHIP_POLARIS10) {
+ adev->asic_type == CHIP_POLARIS10 ||
+ adev->asic_type == CHIP_POLARIS12) {
tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D);
tmp &= ~0x3;
WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp);
@@ -4283,6 +4385,7 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev)
amdgpu_ring_write(ring, 0x0000002A);
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_ring_write(ring, 0x16000012);
amdgpu_ring_write(ring, 0x00000000);
break;
@@ -4489,6 +4592,393 @@ static void gfx_v8_0_cp_compute_fini(struct amdgpu_device *adev)
}
}
+/* KIQ functions */
+static void gfx_v8_0_kiq_setting(struct amdgpu_ring *ring)
+{
+ uint32_t tmp;
+ struct amdgpu_device *adev = ring->adev;
+
+ /* tell RLC which is KIQ queue */
+ tmp = RREG32(mmRLC_CP_SCHEDULERS);
+ tmp &= 0xffffff00;
+ tmp |= (ring->me << 5) | (ring->pipe << 3) | (ring->queue);
+ WREG32(mmRLC_CP_SCHEDULERS, tmp);
+ tmp |= 0x80;
+ WREG32(mmRLC_CP_SCHEDULERS, tmp);
+}
+
+static void gfx_v8_0_kiq_enable(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_alloc(ring, 8);
+ /* set resources */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SET_RESOURCES, 6));
+ amdgpu_ring_write(ring, 0); /* vmid_mask:0 queue_type:0 (KIQ) */
+ amdgpu_ring_write(ring, 0x000000FF); /* queue mask lo */
+ amdgpu_ring_write(ring, 0); /* queue mask hi */
+ amdgpu_ring_write(ring, 0); /* gws mask lo */
+ amdgpu_ring_write(ring, 0); /* gws mask hi */
+ amdgpu_ring_write(ring, 0); /* oac mask */
+ amdgpu_ring_write(ring, 0); /* gds heap base:0, gds heap size:0 */
+ amdgpu_ring_commit(ring);
+ udelay(50);
+}
+
+static void gfx_v8_0_map_queue_enable(struct amdgpu_ring *kiq_ring,
+ struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = kiq_ring->adev;
+ uint64_t mqd_addr, wptr_addr;
+
+ mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj);
+ wptr_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+ amdgpu_ring_alloc(kiq_ring, 8);
+
+ amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_MAP_QUEUES, 5));
+ /* Q_sel:0, vmid:0, vidmem: 1, engine:0, num_Q:1*/
+ amdgpu_ring_write(kiq_ring, 0x21010000);
+ amdgpu_ring_write(kiq_ring, (ring->doorbell_index << 2) |
+ (ring->queue << 26) |
+ (ring->pipe << 29) |
+ ((ring->me == 1 ? 0 : 1) << 31)); /* doorbell */
+ amdgpu_ring_write(kiq_ring, lower_32_bits(mqd_addr));
+ amdgpu_ring_write(kiq_ring, upper_32_bits(mqd_addr));
+ amdgpu_ring_write(kiq_ring, lower_32_bits(wptr_addr));
+ amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
+ amdgpu_ring_commit(kiq_ring);
+ udelay(50);
+}
+
+static int gfx_v8_0_mqd_init(struct amdgpu_device *adev,
+ struct vi_mqd *mqd,
+ uint64_t mqd_gpu_addr,
+ uint64_t eop_gpu_addr,
+ struct amdgpu_ring *ring)
+{
+ uint64_t hqd_gpu_addr, wb_gpu_addr, eop_base_addr;
+ uint32_t tmp;
+
+ mqd->header = 0xC0310800;
+ mqd->compute_pipelinestat_enable = 0x00000001;
+ mqd->compute_static_thread_mgmt_se0 = 0xffffffff;
+ mqd->compute_static_thread_mgmt_se1 = 0xffffffff;
+ mqd->compute_static_thread_mgmt_se2 = 0xffffffff;
+ mqd->compute_static_thread_mgmt_se3 = 0xffffffff;
+ mqd->compute_misc_reserved = 0x00000003;
+
+ eop_base_addr = eop_gpu_addr >> 8;
+ mqd->cp_hqd_eop_base_addr_lo = eop_base_addr;
+ mqd->cp_hqd_eop_base_addr_hi = upper_32_bits(eop_base_addr);
+
+ /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+ tmp = RREG32(mmCP_HQD_EOP_CONTROL);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
+ (order_base_2(MEC_HPD_SIZE / 4) - 1));
+
+ mqd->cp_hqd_eop_control = tmp;
+
+ /* enable doorbell? */
+ tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
+
+ if (ring->use_doorbell)
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_EN, 1);
+ else
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_EN, 0);
+
+ mqd->cp_hqd_pq_doorbell_control = tmp;
+
+ /* disable the queue if it's active */
+ mqd->cp_hqd_dequeue_request = 0;
+ mqd->cp_hqd_pq_rptr = 0;
+ mqd->cp_hqd_pq_wptr = 0;
+
+ /* set the pointer to the MQD */
+ mqd->cp_mqd_base_addr_lo = mqd_gpu_addr & 0xfffffffc;
+ mqd->cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
+
+ /* set MQD vmid to 0 */
+ tmp = RREG32(mmCP_MQD_CONTROL);
+ tmp = REG_SET_FIELD(tmp, CP_MQD_CONTROL, VMID, 0);
+ mqd->cp_mqd_control = tmp;
+
+ /* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+ hqd_gpu_addr = ring->gpu_addr >> 8;
+ mqd->cp_hqd_pq_base_lo = hqd_gpu_addr;
+ mqd->cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+
+ /* set up the HQD, this is similar to CP_RB0_CNTL */
+ tmp = RREG32(mmCP_HQD_PQ_CONTROL);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, QUEUE_SIZE,
+ (order_base_2(ring->ring_size / 4) - 1));
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
+ ((order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1) << 8));
+#ifdef __BIG_ENDIAN
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1);
+#endif
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ROQ_PQ_IB_FLIP, 0);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1);
+ mqd->cp_hqd_pq_control = tmp;
+
+ /* set the wb address whether it's enabled or not */
+ wb_gpu_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+ mqd->cp_hqd_pq_rptr_report_addr_lo = wb_gpu_addr & 0xfffffffc;
+ mqd->cp_hqd_pq_rptr_report_addr_hi =
+ upper_32_bits(wb_gpu_addr) & 0xffff;
+
+ /* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
+ wb_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+ mqd->cp_hqd_pq_wptr_poll_addr_lo = wb_gpu_addr & 0xfffffffc;
+ mqd->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
+
+ tmp = 0;
+ /* enable the doorbell if requested */
+ if (ring->use_doorbell) {
+ tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_OFFSET, ring->doorbell_index);
+
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_EN, 1);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_SOURCE, 0);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
+ DOORBELL_HIT, 0);
+ }
+
+ mqd->cp_hqd_pq_doorbell_control = tmp;
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+ ring->wptr = 0;
+ mqd->cp_hqd_pq_wptr = ring->wptr;
+ mqd->cp_hqd_pq_rptr = RREG32(mmCP_HQD_PQ_RPTR);
+
+ /* set the vmid for the queue */
+ mqd->cp_hqd_vmid = 0;
+
+ tmp = RREG32(mmCP_HQD_PERSISTENT_STATE);
+ tmp = REG_SET_FIELD(tmp, CP_HQD_PERSISTENT_STATE, PRELOAD_SIZE, 0x53);
+ mqd->cp_hqd_persistent_state = tmp;
+
+ /* activate the queue */
+ mqd->cp_hqd_active = 1;
+
+ return 0;
+}
+
+static int gfx_v8_0_kiq_init_register(struct amdgpu_device *adev,
+ struct vi_mqd *mqd,
+ struct amdgpu_ring *ring)
+{
+ uint32_t tmp;
+ int j;
+
+ /* disable wptr polling */
+ tmp = RREG32(mmCP_PQ_WPTR_POLL_CNTL);
+ tmp = REG_SET_FIELD(tmp, CP_PQ_WPTR_POLL_CNTL, EN, 0);
+ WREG32(mmCP_PQ_WPTR_POLL_CNTL, tmp);
+
+ WREG32(mmCP_HQD_EOP_BASE_ADDR, mqd->cp_hqd_eop_base_addr_lo);
+ WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, mqd->cp_hqd_eop_base_addr_hi);
+
+ /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+ WREG32(mmCP_HQD_EOP_CONTROL, mqd->cp_hqd_eop_control);
+
+ /* enable doorbell? */
+ WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, mqd->cp_hqd_pq_doorbell_control);
+
+ /* disable the queue if it's active */
+ if (RREG32(mmCP_HQD_ACTIVE) & 1) {
+ WREG32(mmCP_HQD_DEQUEUE_REQUEST, 1);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ if (!(RREG32(mmCP_HQD_ACTIVE) & 1))
+ break;
+ udelay(1);
+ }
+ WREG32(mmCP_HQD_DEQUEUE_REQUEST, mqd->cp_hqd_dequeue_request);
+ WREG32(mmCP_HQD_PQ_RPTR, mqd->cp_hqd_pq_rptr);
+ WREG32(mmCP_HQD_PQ_WPTR, mqd->cp_hqd_pq_wptr);
+ }
+
+ /* set the pointer to the MQD */
+ WREG32(mmCP_MQD_BASE_ADDR, mqd->cp_mqd_base_addr_lo);
+ WREG32(mmCP_MQD_BASE_ADDR_HI, mqd->cp_mqd_base_addr_hi);
+
+ /* set MQD vmid to 0 */
+ WREG32(mmCP_MQD_CONTROL, mqd->cp_mqd_control);
+
+ /* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+ WREG32(mmCP_HQD_PQ_BASE, mqd->cp_hqd_pq_base_lo);
+ WREG32(mmCP_HQD_PQ_BASE_HI, mqd->cp_hqd_pq_base_hi);
+
+ /* set up the HQD, this is similar to CP_RB0_CNTL */
+ WREG32(mmCP_HQD_PQ_CONTROL, mqd->cp_hqd_pq_control);
+
+ /* set the wb address whether it's enabled or not */
+ WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR,
+ mqd->cp_hqd_pq_rptr_report_addr_lo);
+ WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+ mqd->cp_hqd_pq_rptr_report_addr_hi);
+
+ /* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
+ WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, mqd->cp_hqd_pq_wptr_poll_addr_lo);
+ WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI, mqd->cp_hqd_pq_wptr_poll_addr_hi);
+
+ /* enable the doorbell if requested */
+ if (ring->use_doorbell) {
+ if ((adev->asic_type == CHIP_CARRIZO) ||
+ (adev->asic_type == CHIP_FIJI) ||
+ (adev->asic_type == CHIP_STONEY)) {
+ WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
+ AMDGPU_DOORBELL_KIQ << 2);
+ WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
+ AMDGPU_DOORBELL_MEC_RING7 << 2);
+ }
+ }
+ WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, mqd->cp_hqd_pq_doorbell_control);
+
+ /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+ WREG32(mmCP_HQD_PQ_WPTR, mqd->cp_hqd_pq_wptr);
+
+ /* set the vmid for the queue */
+ WREG32(mmCP_HQD_VMID, mqd->cp_hqd_vmid);
+
+ WREG32(mmCP_HQD_PERSISTENT_STATE, mqd->cp_hqd_persistent_state);
+
+ /* activate the queue */
+ WREG32(mmCP_HQD_ACTIVE, mqd->cp_hqd_active);
+
+ if (ring->use_doorbell) {
+ tmp = RREG32(mmCP_PQ_STATUS);
+ tmp = REG_SET_FIELD(tmp, CP_PQ_STATUS, DOORBELL_ENABLE, 1);
+ WREG32(mmCP_PQ_STATUS, tmp);
+ }
+
+ return 0;
+}
+
+static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring,
+ struct vi_mqd *mqd,
+ u64 mqd_gpu_addr)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ uint64_t eop_gpu_addr;
+ bool is_kiq = false;
+
+ if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
+ is_kiq = true;
+
+ if (is_kiq) {
+ eop_gpu_addr = kiq->eop_gpu_addr;
+ gfx_v8_0_kiq_setting(&kiq->ring);
+ } else
+ eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr +
+ ring->queue * MEC_HPD_SIZE;
+
+ mutex_lock(&adev->srbm_mutex);
+ vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
+
+ gfx_v8_0_mqd_init(adev, mqd, mqd_gpu_addr, eop_gpu_addr, ring);
+
+ if (is_kiq)
+ gfx_v8_0_kiq_init_register(adev, mqd, ring);
+
+ vi_srbm_select(adev, 0, 0, 0, 0);
+ mutex_unlock(&adev->srbm_mutex);
+
+ if (is_kiq)
+ gfx_v8_0_kiq_enable(ring);
+ else
+ gfx_v8_0_map_queue_enable(&kiq->ring, ring);
+
+ return 0;
+}
+
+static void gfx_v8_0_kiq_free_queue(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *ring = NULL;
+ int i;
+
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+ amdgpu_bo_free_kernel(&ring->mqd_obj, NULL, NULL);
+ ring->mqd_obj = NULL;
+ }
+
+ ring = &adev->gfx.kiq.ring;
+ amdgpu_bo_free_kernel(&ring->mqd_obj, NULL, NULL);
+ ring->mqd_obj = NULL;
+}
+
+static int gfx_v8_0_kiq_setup_queue(struct amdgpu_device *adev,
+ struct amdgpu_ring *ring)
+{
+ struct vi_mqd *mqd;
+ u64 mqd_gpu_addr;
+ u32 *buf;
+ int r = 0;
+
+ r = amdgpu_bo_create_kernel(adev, sizeof(struct vi_mqd), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_GTT, &ring->mqd_obj,
+ &mqd_gpu_addr, (void **)&buf);
+ if (r) {
+ dev_warn(adev->dev, "failed to create ring mqd ob (%d)", r);
+ return r;
+ }
+
+ /* init the mqd struct */
+ memset(buf, 0, sizeof(struct vi_mqd));
+ mqd = (struct vi_mqd *)buf;
+
+ r = gfx_v8_0_kiq_init_queue(ring, mqd, mqd_gpu_addr);
+ if (r)
+ return r;
+
+ amdgpu_bo_kunmap(ring->mqd_obj);
+
+ return 0;
+}
+
+static int gfx_v8_0_kiq_resume(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *ring = NULL;
+ int r, i;
+
+ ring = &adev->gfx.kiq.ring;
+ r = gfx_v8_0_kiq_setup_queue(adev, ring);
+ if (r)
+ return r;
+
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+ r = gfx_v8_0_kiq_setup_queue(adev, ring);
+ if (r)
+ return r;
+ }
+
+ gfx_v8_0_cp_compute_enable(adev, true);
+
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+
+ ring->ready = true;
+ r = amdgpu_ring_test_ring(ring);
+ if (r)
+ ring->ready = false;
+ }
+
+ ring = &adev->gfx.kiq.ring;
+ ring->ready = true;
+ r = amdgpu_ring_test_ring(ring);
+ if (r)
+ ring->ready = false;
+
+ return 0;
+}
+
static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
{
int r, i, j;
@@ -4664,7 +5154,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
(adev->asic_type == CHIP_FIJI) ||
(adev->asic_type == CHIP_STONEY) ||
(adev->asic_type == CHIP_POLARIS11) ||
- (adev->asic_type == CHIP_POLARIS10)) {
+ (adev->asic_type == CHIP_POLARIS10) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
AMDGPU_DOORBELL_KIQ << 2);
WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
@@ -4700,7 +5191,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
mqd->cp_hqd_persistent_state = tmp;
if (adev->asic_type == CHIP_STONEY ||
adev->asic_type == CHIP_POLARIS11 ||
- adev->asic_type == CHIP_POLARIS10) {
+ adev->asic_type == CHIP_POLARIS10 ||
+ adev->asic_type == CHIP_POLARIS12) {
tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL);
tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1);
WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp);
@@ -4787,7 +5279,10 @@ static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
if (r)
return r;
- r = gfx_v8_0_cp_compute_resume(adev);
+ if (amdgpu_sriov_vf(adev))
+ r = gfx_v8_0_kiq_resume(adev);
+ else
+ r = gfx_v8_0_cp_compute_resume(adev);
if (r)
return r;
@@ -4826,6 +5321,7 @@ static int gfx_v8_0_hw_fini(void *handle)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
if (amdgpu_sriov_vf(adev)) {
+ gfx_v8_0_kiq_free_queue(adev);
pr_debug("For SRIOV client, shouldn't do anything.\n");
return 0;
}
@@ -5279,7 +5775,8 @@ static int gfx_v8_0_late_init(void *handle)
static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev,
bool enable)
{
- if (adev->asic_type == CHIP_POLARIS11)
+ if ((adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12))
/* Send msg to SMU via Powerplay */
amdgpu_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_SMC,
@@ -5340,6 +5837,18 @@ static int gfx_v8_0_set_powergating_state(void *handle,
case CHIP_CARRIZO:
case CHIP_STONEY:
+ if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) {
+ cz_enable_sck_slow_down_on_power_up(adev, true);
+ cz_enable_sck_slow_down_on_power_down(adev, true);
+ } else {
+ cz_enable_sck_slow_down_on_power_up(adev, false);
+ cz_enable_sck_slow_down_on_power_down(adev, false);
+ }
+ if (adev->pg_flags & AMD_PG_SUPPORT_CP)
+ cz_enable_cp_power_gating(adev, true);
+ else
+ cz_enable_cp_power_gating(adev, false);
+
cz_update_gfx_cg_power_gating(adev, enable);
if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable)
@@ -5353,6 +5862,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false);
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable)
gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true);
else
@@ -5375,6 +5885,45 @@ static int gfx_v8_0_set_powergating_state(void *handle,
return 0;
}
+static void gfx_v8_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ /* AMD_CG_SUPPORT_GFX_MGCG */
+ data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ if (!(data & RLC_CGTT_MGCG_OVERRIDE__CPF_MASK))
+ *flags |= AMD_CG_SUPPORT_GFX_MGCG;
+
+ /* AMD_CG_SUPPORT_GFX_CGLG */
+ data = RREG32(mmRLC_CGCG_CGLS_CTRL);
+ if (data & RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK)
+ *flags |= AMD_CG_SUPPORT_GFX_CGCG;
+
+ /* AMD_CG_SUPPORT_GFX_CGLS */
+ if (data & RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK)
+ *flags |= AMD_CG_SUPPORT_GFX_CGLS;
+
+ /* AMD_CG_SUPPORT_GFX_CGTS */
+ data = RREG32(mmCGTS_SM_CTRL_REG);
+ if (!(data & CGTS_SM_CTRL_REG__OVERRIDE_MASK))
+ *flags |= AMD_CG_SUPPORT_GFX_CGTS;
+
+ /* AMD_CG_SUPPORT_GFX_CGTS_LS */
+ if (!(data & CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK))
+ *flags |= AMD_CG_SUPPORT_GFX_CGTS_LS;
+
+ /* AMD_CG_SUPPORT_GFX_RLC_LS */
+ data = RREG32(mmRLC_MEM_SLP_CNTL);
+ if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK)
+ *flags |= AMD_CG_SUPPORT_GFX_RLC_LS | AMD_CG_SUPPORT_GFX_MGLS;
+
+ /* AMD_CG_SUPPORT_GFX_CP_LS */
+ data = RREG32(mmCP_MEM_SLP_CNTL);
+ if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK)
+ *flags |= AMD_CG_SUPPORT_GFX_CP_LS | AMD_CG_SUPPORT_GFX_MGLS;
+}
+
static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
uint32_t reg_addr, uint32_t cmd)
{
@@ -5423,68 +5972,6 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
#define RLC_GPR_REG2__MESSAGE__SHIFT 0x00000001
#define RLC_GPR_REG2__MESSAGE_MASK 0x0000001e
-static void cz_enter_rlc_safe_mode(struct amdgpu_device *adev)
-{
- u32 data = 0;
- unsigned i;
-
- data = RREG32(mmRLC_CNTL);
- if ((data & RLC_CNTL__RLC_ENABLE_F32_MASK) == 0)
- return;
-
- if ((adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) ||
- (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_GFX_SMG |
- AMD_PG_SUPPORT_GFX_DMG))) {
- data |= RLC_GPR_REG2__REQ_MASK;
- data &= ~RLC_GPR_REG2__MESSAGE_MASK;
- data |= (MSG_ENTER_RLC_SAFE_MODE << RLC_GPR_REG2__MESSAGE__SHIFT);
- WREG32(mmRLC_GPR_REG2, data);
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if ((RREG32(mmRLC_GPM_STAT) &
- (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
- RLC_GPM_STAT__GFX_POWER_STATUS_MASK)) ==
- (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
- RLC_GPM_STAT__GFX_POWER_STATUS_MASK))
- break;
- udelay(1);
- }
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ))
- break;
- udelay(1);
- }
- adev->gfx.rlc.in_safe_mode = true;
- }
-}
-
-static void cz_exit_rlc_safe_mode(struct amdgpu_device *adev)
-{
- u32 data;
- unsigned i;
-
- data = RREG32(mmRLC_CNTL);
- if ((data & RLC_CNTL__RLC_ENABLE_F32_MASK) == 0)
- return;
-
- if ((adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) ||
- (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_GFX_SMG |
- AMD_PG_SUPPORT_GFX_DMG))) {
- data |= RLC_GPR_REG2__REQ_MASK;
- data &= ~RLC_GPR_REG2__MESSAGE_MASK;
- data |= (MSG_EXIT_RLC_SAFE_MODE << RLC_GPR_REG2__MESSAGE__SHIFT);
- WREG32(mmRLC_GPR_REG2, data);
- adev->gfx.rlc.in_safe_mode = false;
- }
-
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ))
- break;
- udelay(1);
- }
-}
-
static void iceland_enter_rlc_safe_mode(struct amdgpu_device *adev)
{
u32 data;
@@ -5544,31 +6031,11 @@ static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
}
}
-static void gfx_v8_0_nop_enter_rlc_safe_mode(struct amdgpu_device *adev)
-{
- adev->gfx.rlc.in_safe_mode = true;
-}
-
-static void gfx_v8_0_nop_exit_rlc_safe_mode(struct amdgpu_device *adev)
-{
- adev->gfx.rlc.in_safe_mode = false;
-}
-
-static const struct amdgpu_rlc_funcs cz_rlc_funcs = {
- .enter_safe_mode = cz_enter_rlc_safe_mode,
- .exit_safe_mode = cz_exit_rlc_safe_mode
-};
-
static const struct amdgpu_rlc_funcs iceland_rlc_funcs = {
.enter_safe_mode = iceland_enter_rlc_safe_mode,
.exit_safe_mode = iceland_exit_rlc_safe_mode
};
-static const struct amdgpu_rlc_funcs gfx_v8_0_nop_rlc_funcs = {
- .enter_safe_mode = gfx_v8_0_nop_enter_rlc_safe_mode,
- .exit_safe_mode = gfx_v8_0_nop_exit_rlc_safe_mode
-};
-
static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
bool enable)
{
@@ -5990,7 +6457,8 @@ static void gfx_v8_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
{
u32 ref_and_mask, reg_mem_engine;
- if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) {
+ if ((ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) ||
+ (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)) {
switch (ring->me) {
case 1:
ref_and_mask = GPU_HDP_FLUSH_DONE__CP2_MASK << ring->pipe;
@@ -6203,6 +6671,31 @@ static void gfx_v8_0_ring_emit_fence_compute(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, upper_32_bits(seq));
}
+static void gfx_v8_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
+ u64 seq, unsigned int flags)
+{
+ /* we only allocate 32bit for each seq wb address */
+ BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+
+ /* write fence seq to the "addr" */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(5) | WR_CONFIRM));
+ amdgpu_ring_write(ring, lower_32_bits(addr));
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, lower_32_bits(seq));
+
+ if (flags & AMDGPU_FENCE_FLAG_INT) {
+ /* set register to trigger INT */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0) | WR_CONFIRM));
+ amdgpu_ring_write(ring, mmCPC_INT_STATUS);
+ amdgpu_ring_write(ring, 0);
+ amdgpu_ring_write(ring, 0x20000000); /* src_id is 178 */
+ }
+}
+
static void gfx_v8_ring_emit_sb(struct amdgpu_ring *ring)
{
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
@@ -6213,6 +6706,10 @@ static void gfx_v8_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
{
uint32_t dw2 = 0;
+ if (amdgpu_sriov_vf(ring->adev))
+ gfx_v8_0_ring_emit_ce_meta_init(ring,
+ (flags & AMDGPU_VM_DOMAIN) ? AMDGPU_CSA_VADDR : ring->adev->virt.csa_vmid0_addr);
+
dw2 |= 0x80000000; /* set load_enable otherwise this package is just NOPs */
if (flags & AMDGPU_HAVE_CTX_SWITCH) {
gfx_v8_0_ring_emit_vgt_flush(ring);
@@ -6237,6 +6734,36 @@ static void gfx_v8_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
amdgpu_ring_write(ring, dw2);
amdgpu_ring_write(ring, 0);
+
+ if (amdgpu_sriov_vf(ring->adev))
+ gfx_v8_0_ring_emit_de_meta_init(ring,
+ (flags & AMDGPU_VM_DOMAIN) ? AMDGPU_CSA_VADDR : ring->adev->virt.csa_vmid0_addr);
+}
+
+static void gfx_v8_0_ring_emit_rreg(struct amdgpu_ring *ring, uint32_t reg)
+{
+ struct amdgpu_device *adev = ring->adev;
+
+ amdgpu_ring_write(ring, PACKET3(PACKET3_COPY_DATA, 4));
+ amdgpu_ring_write(ring, 0 | /* src: register*/
+ (5 << 8) | /* dst: memory */
+ (1 << 20)); /* write confirm */
+ amdgpu_ring_write(ring, reg);
+ amdgpu_ring_write(ring, 0);
+ amdgpu_ring_write(ring, lower_32_bits(adev->wb.gpu_addr +
+ adev->virt.reg_val_offs * 4));
+ amdgpu_ring_write(ring, upper_32_bits(adev->wb.gpu_addr +
+ adev->virt.reg_val_offs * 4));
+}
+
+static void gfx_v8_0_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg,
+ uint32_t val)
+{
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ amdgpu_ring_write(ring, (1 << 16)); /* no inc addr */
+ amdgpu_ring_write(ring, reg);
+ amdgpu_ring_write(ring, 0);
+ amdgpu_ring_write(ring, val);
}
static void gfx_v8_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
@@ -6384,6 +6911,72 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
return 0;
}
+static int gfx_v8_0_kiq_set_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned int type,
+ enum amdgpu_interrupt_state state)
+{
+ uint32_t tmp, target;
+ struct amdgpu_ring *ring = (struct amdgpu_ring *)src->data;
+
+ BUG_ON(!ring || (ring->funcs->type != AMDGPU_RING_TYPE_KIQ));
+
+ if (ring->me == 1)
+ target = mmCP_ME1_PIPE0_INT_CNTL;
+ else
+ target = mmCP_ME2_PIPE0_INT_CNTL;
+ target += ring->pipe;
+
+ switch (type) {
+ case AMDGPU_CP_KIQ_IRQ_DRIVER0:
+ if (state == AMDGPU_IRQ_STATE_DISABLE) {
+ tmp = RREG32(mmCPC_INT_CNTL);
+ tmp = REG_SET_FIELD(tmp, CPC_INT_CNTL,
+ GENERIC2_INT_ENABLE, 0);
+ WREG32(mmCPC_INT_CNTL, tmp);
+
+ tmp = RREG32(target);
+ tmp = REG_SET_FIELD(tmp, CP_ME2_PIPE0_INT_CNTL,
+ GENERIC2_INT_ENABLE, 0);
+ WREG32(target, tmp);
+ } else {
+ tmp = RREG32(mmCPC_INT_CNTL);
+ tmp = REG_SET_FIELD(tmp, CPC_INT_CNTL,
+ GENERIC2_INT_ENABLE, 1);
+ WREG32(mmCPC_INT_CNTL, tmp);
+
+ tmp = RREG32(target);
+ tmp = REG_SET_FIELD(tmp, CP_ME2_PIPE0_INT_CNTL,
+ GENERIC2_INT_ENABLE, 1);
+ WREG32(target, tmp);
+ }
+ break;
+ default:
+ BUG(); /* kiq only support GENERIC2_INT now */
+ break;
+ }
+ return 0;
+}
+
+static int gfx_v8_0_kiq_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ u8 me_id, pipe_id, queue_id;
+ struct amdgpu_ring *ring = (struct amdgpu_ring *)source->data;
+
+ BUG_ON(!ring || (ring->funcs->type != AMDGPU_RING_TYPE_KIQ));
+
+ me_id = (entry->ring_id & 0x0c) >> 2;
+ pipe_id = (entry->ring_id & 0x03) >> 0;
+ queue_id = (entry->ring_id & 0x70) >> 4;
+ DRM_DEBUG("IH: CPC GENERIC2_INT, me:%d, pipe:%d, queue:%d\n",
+ me_id, pipe_id, queue_id);
+
+ amdgpu_fence_process(ring);
+ return 0;
+}
+
static const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
.name = "gfx_v8_0",
.early_init = gfx_v8_0_early_init,
@@ -6402,6 +6995,7 @@ static const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
.post_soft_reset = gfx_v8_0_post_soft_reset,
.set_clockgating_state = gfx_v8_0_set_clockgating_state,
.set_powergating_state = gfx_v8_0_set_powergating_state,
+ .get_clockgating_state = gfx_v8_0_get_clockgating_state,
};
static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
@@ -6419,7 +7013,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
7 + /* gfx_v8_0_ring_emit_pipeline_sync */
128 + 19 + /* gfx_v8_0_ring_emit_vm_flush */
2 + /* gfx_v8_ring_emit_sb */
- 3 + 4, /* gfx_v8_ring_emit_cntxcntl including vgt flush */
+ 3 + 4 + 29, /* gfx_v8_ring_emit_cntxcntl including vgt flush/meta-data */
.emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_gfx */
.emit_ib = gfx_v8_0_ring_emit_ib_gfx,
.emit_fence = gfx_v8_0_ring_emit_fence_gfx,
@@ -6464,10 +7058,39 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
.pad_ib = amdgpu_ring_generic_pad_ib,
};
+static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = {
+ .type = AMDGPU_RING_TYPE_KIQ,
+ .align_mask = 0xff,
+ .nop = PACKET3(PACKET3_NOP, 0x3FFF),
+ .get_rptr = gfx_v8_0_ring_get_rptr,
+ .get_wptr = gfx_v8_0_ring_get_wptr_compute,
+ .set_wptr = gfx_v8_0_ring_set_wptr_compute,
+ .emit_frame_size =
+ 20 + /* gfx_v8_0_ring_emit_gds_switch */
+ 7 + /* gfx_v8_0_ring_emit_hdp_flush */
+ 5 + /* gfx_v8_0_ring_emit_hdp_invalidate */
+ 7 + /* gfx_v8_0_ring_emit_pipeline_sync */
+ 17 + /* gfx_v8_0_ring_emit_vm_flush */
+ 7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_kiq x3 for user fence, vm fence */
+ .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */
+ .emit_ib = gfx_v8_0_ring_emit_ib_compute,
+ .emit_fence = gfx_v8_0_ring_emit_fence_kiq,
+ .emit_hdp_flush = gfx_v8_0_ring_emit_hdp_flush,
+ .emit_hdp_invalidate = gfx_v8_0_ring_emit_hdp_invalidate,
+ .test_ring = gfx_v8_0_ring_test_ring,
+ .test_ib = gfx_v8_0_ring_test_ib,
+ .insert_nop = amdgpu_ring_insert_nop,
+ .pad_ib = amdgpu_ring_generic_pad_ib,
+ .emit_rreg = gfx_v8_0_ring_emit_rreg,
+ .emit_wreg = gfx_v8_0_ring_emit_wreg,
+};
+
static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev)
{
int i;
+ adev->gfx.kiq.ring.funcs = &gfx_v8_0_ring_funcs_kiq;
+
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
adev->gfx.gfx_ring[i].funcs = &gfx_v8_0_ring_funcs_gfx;
@@ -6490,6 +7113,11 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_priv_inst_irq_funcs = {
.process = gfx_v8_0_priv_inst_irq,
};
+static const struct amdgpu_irq_src_funcs gfx_v8_0_kiq_irq_funcs = {
+ .set = gfx_v8_0_kiq_set_interrupt_state,
+ .process = gfx_v8_0_kiq_irq,
+};
+
static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
{
adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST;
@@ -6500,22 +7128,14 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
adev->gfx.priv_inst_irq.num_types = 1;
adev->gfx.priv_inst_irq.funcs = &gfx_v8_0_priv_inst_irq_funcs;
+
+ adev->gfx.kiq.irq.num_types = AMDGPU_CP_KIQ_IRQ_LAST;
+ adev->gfx.kiq.irq.funcs = &gfx_v8_0_kiq_irq_funcs;
}
static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev)
{
- switch (adev->asic_type) {
- case CHIP_TOPAZ:
- adev->gfx.rlc.funcs = &iceland_rlc_funcs;
- break;
- case CHIP_STONEY:
- case CHIP_CARRIZO:
- adev->gfx.rlc.funcs = &cz_rlc_funcs;
- break;
- default:
- adev->gfx.rlc.funcs = &gfx_v8_0_nop_rlc_funcs;
- break;
- }
+ adev->gfx.rlc.funcs = &iceland_rlc_funcs;
}
static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev)
@@ -6632,3 +7252,62 @@ const struct amdgpu_ip_block_version gfx_v8_1_ip_block =
.rev = 0,
.funcs = &gfx_v8_0_ip_funcs,
};
+
+static void gfx_v8_0_ring_emit_ce_meta_init(struct amdgpu_ring *ring, uint64_t csa_addr)
+{
+ uint64_t ce_payload_addr;
+ int cnt_ce;
+ static union {
+ struct amdgpu_ce_ib_state regular;
+ struct amdgpu_ce_ib_state_chained_ib chained;
+ } ce_payload = {0};
+
+ if (ring->adev->virt.chained_ib_support) {
+ ce_payload_addr = csa_addr + offsetof(struct amdgpu_gfx_meta_data_chained_ib, ce_payload);
+ cnt_ce = (sizeof(ce_payload.chained) >> 2) + 4 - 2;
+ } else {
+ ce_payload_addr = csa_addr + offsetof(struct amdgpu_gfx_meta_data, ce_payload);
+ cnt_ce = (sizeof(ce_payload.regular) >> 2) + 4 - 2;
+ }
+
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, cnt_ce));
+ amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(2) |
+ WRITE_DATA_DST_SEL(8) |
+ WR_CONFIRM) |
+ WRITE_DATA_CACHE_POLICY(0));
+ amdgpu_ring_write(ring, lower_32_bits(ce_payload_addr));
+ amdgpu_ring_write(ring, upper_32_bits(ce_payload_addr));
+ amdgpu_ring_write_multiple(ring, (void *)&ce_payload, cnt_ce - 2);
+}
+
+static void gfx_v8_0_ring_emit_de_meta_init(struct amdgpu_ring *ring, uint64_t csa_addr)
+{
+ uint64_t de_payload_addr, gds_addr;
+ int cnt_de;
+ static union {
+ struct amdgpu_de_ib_state regular;
+ struct amdgpu_de_ib_state_chained_ib chained;
+ } de_payload = {0};
+
+ gds_addr = csa_addr + 4096;
+ if (ring->adev->virt.chained_ib_support) {
+ de_payload.chained.gds_backup_addrlo = lower_32_bits(gds_addr);
+ de_payload.chained.gds_backup_addrhi = upper_32_bits(gds_addr);
+ de_payload_addr = csa_addr + offsetof(struct amdgpu_gfx_meta_data_chained_ib, de_payload);
+ cnt_de = (sizeof(de_payload.chained) >> 2) + 4 - 2;
+ } else {
+ de_payload.regular.gds_backup_addrlo = lower_32_bits(gds_addr);
+ de_payload.regular.gds_backup_addrhi = upper_32_bits(gds_addr);
+ de_payload_addr = csa_addr + offsetof(struct amdgpu_gfx_meta_data, de_payload);
+ cnt_de = (sizeof(de_payload.regular) >> 2) + 4 - 2;
+ }
+
+ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, cnt_de));
+ amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
+ WRITE_DATA_DST_SEL(8) |
+ WR_CONFIRM) |
+ WRITE_DATA_CACHE_POLICY(0));
+ amdgpu_ring_write(ring, lower_32_bits(de_payload_addr));
+ amdgpu_ring_write(ring, upper_32_bits(de_payload_addr));
+ amdgpu_ring_write_multiple(ring, (void *)&de_payload, cnt_de - 2);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index 45a573e63d4a..e2b0b1646f99 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -44,6 +44,7 @@ MODULE_FIRMWARE("radeon/tahiti_mc.bin");
MODULE_FIRMWARE("radeon/pitcairn_mc.bin");
MODULE_FIRMWARE("radeon/verde_mc.bin");
MODULE_FIRMWARE("radeon/oland_mc.bin");
+MODULE_FIRMWARE("radeon/si58_mc.bin");
#define MC_SEQ_MISC0__MT__MASK 0xf0000000
#define MC_SEQ_MISC0__MT__GDDR1 0x10000000
@@ -113,6 +114,7 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
const char *chip_name;
char fw_name[30];
int err;
+ bool is_58_fw = false;
DRM_DEBUG("\n");
@@ -135,7 +137,14 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
default: BUG();
}
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+ /* this memory configuration requires special firmware */
+ if (((RREG32(mmMC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58)
+ is_58_fw = true;
+
+ if (is_58_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin");
+ else
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
err = request_firmware(&adev->mc.fw, fw_name, adev->dev);
if (err)
goto out;
@@ -463,19 +472,11 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev)
WREG32(mmVM_CONTEXT1_CNTL,
VM_CONTEXT1_CNTL__ENABLE_CONTEXT_MASK |
(1UL << VM_CONTEXT1_CNTL__PAGE_TABLE_DEPTH__SHIFT) |
- ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT) |
- VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK);
+ ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT));
+ if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS)
+ gmc_v6_0_set_fault_enable_default(adev, false);
+ else
+ gmc_v6_0_set_fault_enable_default(adev, true);
gmc_v6_0_gart_flush_gpu_tlb(adev, 0);
dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n",
@@ -754,7 +755,10 @@ static int gmc_v6_0_late_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
+ if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS)
+ return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
+ else
+ return 0;
}
static int gmc_v6_0_sw_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 273b16fb9459..8d05e0c4e3d7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -375,9 +375,16 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
/* size in MB on si */
adev->mc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
- adev->mc.visible_vram_size = adev->mc.aper_size;
+
+#ifdef CONFIG_X86_64
+ if (adev->flags & AMD_IS_APU) {
+ adev->mc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22;
+ adev->mc.aper_size = adev->mc.real_vram_size;
+ }
+#endif
/* In case the PCI BAR is larger than the actual amount of vram */
+ adev->mc.visible_vram_size = adev->mc.aper_size;
if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
adev->mc.visible_vram_size = adev->mc.real_vram_size;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 0daac3a5be79..7669b3259f35 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -46,6 +46,7 @@ static int gmc_v8_0_wait_for_idle(void *handle);
MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
MODULE_FIRMWARE("amdgpu/polaris11_mc.bin");
MODULE_FIRMWARE("amdgpu/polaris10_mc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mc.bin");
static const u32 golden_settings_tonga_a11[] =
{
@@ -130,6 +131,7 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
(const u32)ARRAY_SIZE(golden_settings_tonga_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -225,6 +227,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev)
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_FIJI:
case CHIP_CARRIZO:
case CHIP_STONEY:
@@ -462,9 +467,16 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
/* size in MB on si */
adev->mc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
- adev->mc.visible_vram_size = adev->mc.aper_size;
+
+#ifdef CONFIG_X86_64
+ if (adev->flags & AMD_IS_APU) {
+ adev->mc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22;
+ adev->mc.aper_size = adev->mc.real_vram_size;
+ }
+#endif
/* In case the PCI BAR is larger than the actual amount of vram */
+ adev->mc.visible_vram_size = adev->mc.aper_size;
if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
adev->mc.visible_vram_size = adev->mc.real_vram_size;
@@ -1434,6 +1446,21 @@ static int gmc_v8_0_set_powergating_state(void *handle,
return 0;
}
+static void gmc_v8_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ /* AMD_CG_SUPPORT_MC_MGCG */
+ data = RREG32(mmMC_HUB_MISC_HUB_CG);
+ if (data & MC_HUB_MISC_HUB_CG__ENABLE_MASK)
+ *flags |= AMD_CG_SUPPORT_MC_MGCG;
+
+ /* AMD_CG_SUPPORT_MC_LS */
+ if (data & MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK)
+ *flags |= AMD_CG_SUPPORT_MC_LS;
+}
+
static const struct amd_ip_funcs gmc_v8_0_ip_funcs = {
.name = "gmc_v8_0",
.early_init = gmc_v8_0_early_init,
@@ -1452,6 +1479,7 @@ static const struct amd_ip_funcs gmc_v8_0_ip_funcs = {
.post_soft_reset = gmc_v8_0_post_soft_reset,
.set_clockgating_state = gmc_v8_0_set_clockgating_state,
.set_powergating_state = gmc_v8_0_set_powergating_state,
+ .get_clockgating_state = gmc_v8_0_get_clockgating_state,
};
static const struct amdgpu_gart_funcs gmc_v8_0_gart_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
index 5a1bc358bcb1..8785ca570729 100644
--- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
@@ -1230,6 +1230,7 @@ static void kv_update_current_ps(struct amdgpu_device *adev,
pi->current_rps = *rps;
pi->current_ps = *new_ps;
pi->current_rps.ps_priv = &pi->current_ps;
+ adev->pm.dpm.current_ps = &pi->current_rps;
}
static void kv_update_requested_ps(struct amdgpu_device *adev,
@@ -1241,6 +1242,7 @@ static void kv_update_requested_ps(struct amdgpu_device *adev,
pi->requested_rps = *rps;
pi->requested_ps = *new_ps;
pi->requested_rps.ps_priv = &pi->requested_ps;
+ adev->pm.dpm.requested_ps = &pi->requested_rps;
}
static void kv_dpm_enable_bapm(struct amdgpu_device *adev, bool enable)
@@ -1904,19 +1906,19 @@ static int kv_enable_nb_dpm(struct amdgpu_device *adev,
}
static int kv_dpm_force_performance_level(struct amdgpu_device *adev,
- enum amdgpu_dpm_forced_level level)
+ enum amd_dpm_forced_level level)
{
int ret;
- if (level == AMDGPU_DPM_FORCED_LEVEL_HIGH) {
+ if (level == AMD_DPM_FORCED_LEVEL_HIGH) {
ret = kv_force_dpm_highest(adev);
if (ret)
return ret;
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_LOW) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_LOW) {
ret = kv_force_dpm_lowest(adev);
if (ret)
return ret;
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_AUTO) {
ret = kv_unforce_levels(adev);
if (ret)
return ret;
@@ -3009,7 +3011,6 @@ static int kv_dpm_late_init(void *handle)
kv_dpm_powergate_samu(adev, true);
kv_dpm_powergate_vce(adev, true);
kv_dpm_powergate_uvd(adev, true);
-
return 0;
}
@@ -3029,7 +3030,7 @@ static int kv_dpm_sw_init(void *handle)
/* default to balanced state */
adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ adev->pm.dpm.forced_level = AMD_DPM_FORCED_LEVEL_AUTO;
adev->pm.default_sclk = adev->clock.default_sclk;
adev->pm.default_mclk = adev->clock.default_mclk;
adev->pm.current_sclk = adev->clock.default_sclk;
@@ -3078,6 +3079,9 @@ static int kv_dpm_hw_init(void *handle)
int ret;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ if (!amdgpu_dpm)
+ return 0;
+
mutex_lock(&adev->pm.mutex);
kv_dpm_setup_asic(adev);
ret = kv_dpm_enable(adev);
@@ -3245,15 +3249,52 @@ static int kv_dpm_set_powergating_state(void *handle,
return 0;
}
+static inline bool kv_are_power_levels_equal(const struct kv_pl *kv_cpl1,
+ const struct kv_pl *kv_cpl2)
+{
+ return ((kv_cpl1->sclk == kv_cpl2->sclk) &&
+ (kv_cpl1->vddc_index == kv_cpl2->vddc_index) &&
+ (kv_cpl1->ds_divider_index == kv_cpl2->ds_divider_index) &&
+ (kv_cpl1->force_nbp_state == kv_cpl2->force_nbp_state));
+}
+
static int kv_check_state_equal(struct amdgpu_device *adev,
struct amdgpu_ps *cps,
struct amdgpu_ps *rps,
bool *equal)
{
- if (equal == NULL)
+ struct kv_ps *kv_cps;
+ struct kv_ps *kv_rps;
+ int i;
+
+ if (adev == NULL || cps == NULL || rps == NULL || equal == NULL)
return -EINVAL;
- *equal = false;
+ kv_cps = kv_get_ps(cps);
+ kv_rps = kv_get_ps(rps);
+
+ if (kv_cps == NULL) {
+ *equal = false;
+ return 0;
+ }
+
+ if (kv_cps->num_levels != kv_rps->num_levels) {
+ *equal = false;
+ return 0;
+ }
+
+ for (i = 0; i < kv_cps->num_levels; i++) {
+ if (!kv_are_power_levels_equal(&(kv_cps->levels[i]),
+ &(kv_rps->levels[i]))) {
+ *equal = false;
+ return 0;
+ }
+ }
+
+ /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
+ *equal = ((cps->vclk == rps->vclk) && (cps->dclk == rps->dclk));
+ *equal &= ((cps->evclk == rps->evclk) && (cps->ecclk == rps->ecclk));
+
return 0;
}
@@ -3307,12 +3348,3 @@ static void kv_dpm_set_irq_funcs(struct amdgpu_device *adev)
adev->pm.dpm.thermal.irq.num_types = AMDGPU_THERMAL_IRQ_LAST;
adev->pm.dpm.thermal.irq.funcs = &kv_dpm_irq_funcs;
}
-
-const struct amdgpu_ip_block_version kv_dpm_ip_block =
-{
- .type = AMD_IP_BLOCK_TYPE_SMC,
- .major = 7,
- .minor = 0,
- .rev = 0,
- .funcs = &kv_dpm_ip_funcs,
-};
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c
new file mode 100644
index 000000000000..d2622b6f49fa
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Xiangliang.Yu@amd.com
+ */
+
+#include "amdgpu.h"
+#include "vi.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "vid.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+#include "gmc_v8_0.h"
+#include "gfx_v8_0.h"
+#include "sdma_v3_0.h"
+#include "tonga_ih.h"
+#include "gmc/gmc_8_2_d.h"
+#include "gmc/gmc_8_2_sh_mask.h"
+#include "oss/oss_3_0_d.h"
+#include "oss/oss_3_0_sh_mask.h"
+#include "gca/gfx_8_0_sh_mask.h"
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "smu/smu_7_1_3_d.h"
+#include "mxgpu_vi.h"
+
+/* VI golden setting */
+static const u32 xgpu_fiji_mgcg_cgcg_init[] = {
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xffffffff,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100,
+ mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_WD_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL4, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c,
+ mmPCIE_INDEX, 0xffffffff, 0x0140001c,
+ mmPCIE_DATA, 0x000f0000, 0x00000000,
+ mmSMC_IND_INDEX_4, 0xffffffff, 0xC060000C,
+ mmSMC_IND_DATA_4, 0xc0000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
+ mmSDMA0_CLK_CTRL, 0xff000ff0, 0x00000100,
+ mmSDMA1_CLK_CTRL, 0xff000ff0, 0x00000100,
+};
+
+static const u32 xgpu_fiji_golden_settings_a10[] = {
+ mmCB_HW_CONTROL_3, 0x000001ff, 0x00000040,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x1f311fff, 0x12300000,
+ mmHDMI_CONTROL, 0x31000111, 0x00000011,
+ mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmSDMA0_CHICKEN_BITS, 0xfc910007, 0x00810007,
+ mmSDMA0_GFX_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA0_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA0_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_CHICKEN_BITS, 0xfc910007, 0x00810007,
+ mmSDMA1_GFX_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
+ mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
+ mmTCC_EXE_DISABLE, 0x00000002, 0x00000002,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000ff,
+ mmVGT_RESET_DEBUG, 0x00000004, 0x00000004,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+};
+
+static const u32 xgpu_fiji_golden_common_all[] = {
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmPA_SC_RASTER_CONFIG, 0xffffffff, 0x3a00161a,
+ mmPA_SC_RASTER_CONFIG_1, 0xffffffff, 0x0000002e,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x22011003,
+ mmSPI_RESOURCE_RESERVE_CU_0, 0xffffffff, 0x00000800,
+ mmSPI_RESOURCE_RESERVE_CU_1, 0xffffffff, 0x00000800,
+ mmSPI_RESOURCE_RESERVE_EN_CU_0, 0xffffffff, 0x00007FBF,
+ mmSPI_RESOURCE_RESERVE_EN_CU_1, 0xffffffff, 0x00007FAF,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmSPI_CONFIG_CNTL_1, 0x0000000f, 0x00000009,
+};
+
+static const u32 xgpu_tonga_mgcg_cgcg_init[] = {
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xffffffff,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100,
+ mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_WD_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL4, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCGTS_CU0_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU0_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU0_TA_SQC_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU0_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU0_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU1_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU1_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU1_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU1_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU1_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU2_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU2_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU2_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU2_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU2_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU3_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU3_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU3_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU3_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU3_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU4_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU4_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU4_TA_SQC_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU4_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU4_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU5_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU5_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU5_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU5_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU5_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU6_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU6_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU6_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU6_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU6_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_CU7_SP0_CTRL_REG, 0xffffffff, 0x00010000,
+ mmCGTS_CU7_LDS_SQ_CTRL_REG, 0xffffffff, 0x00030002,
+ mmCGTS_CU7_TA_CTRL_REG, 0xffffffff, 0x00040007,
+ mmCGTS_CU7_SP1_CTRL_REG, 0xffffffff, 0x00060005,
+ mmCGTS_CU7_TD_TCP_CTRL_REG, 0xffffffff, 0x00090008,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c,
+ mmPCIE_INDEX, 0xffffffff, 0x0140001c,
+ mmPCIE_DATA, 0x000f0000, 0x00000000,
+ mmSMC_IND_INDEX_4, 0xffffffff, 0xC060000C,
+ mmSMC_IND_DATA_4, 0xc0000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
+ mmSDMA0_CLK_CTRL, 0xff000ff0, 0x00000100,
+ mmSDMA1_CLK_CTRL, 0xff000ff0, 0x00000100,
+};
+
+static const u32 xgpu_tonga_golden_settings_a11[] = {
+ mmCB_HW_CONTROL, 0xfffdf3cf, 0x00007208,
+ mmCB_HW_CONTROL_3, 0x00000040, 0x00000040,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x1f311fff, 0x12300000,
+ mmGB_GPU_ID, 0x0000000f, 0x00000000,
+ mmHDMI_CONTROL, 0x31000111, 0x00000011,
+ mmMC_ARB_WTM_GRPWT_RD, 0x00000003, 0x00000000,
+ mmMC_HUB_RDREQ_DMIF_LIMIT, 0x0000007f, 0x00000028,
+ mmMC_HUB_WDP_UMC, 0x00007fb6, 0x00000991,
+ mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
+ mmPA_SC_FIFO_DEPTH_CNTL, 0x000003ff, 0x000000fc,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0000003c,
+ mmSDMA0_CHICKEN_BITS, 0xfc910007, 0x00810007,
+ mmSDMA0_CLK_CTRL, 0xff000fff, 0x00000000,
+ mmSDMA0_GFX_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA0_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA0_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_CHICKEN_BITS, 0xfc910007, 0x00810007,
+ mmSDMA1_CLK_CTRL, 0xff000fff, 0x00000000,
+ mmSDMA1_GFX_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSDMA1_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
+ mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
+ mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
+ mmTCC_CTRL, 0x00100000, 0xf31fff7f,
+ mmTCC_EXE_DISABLE, 0x00000002, 0x00000002,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x000002fb,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x0000543b,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0xa9210876,
+ mmVGT_RESET_DEBUG, 0x00000004, 0x00000004,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+};
+
+static const u32 xgpu_tonga_golden_common_all[] = {
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmPA_SC_RASTER_CONFIG, 0xffffffff, 0x16000012,
+ mmPA_SC_RASTER_CONFIG_1, 0xffffffff, 0x0000002A,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x22011002,
+ mmSPI_RESOURCE_RESERVE_CU_0, 0xffffffff, 0x00000800,
+ mmSPI_RESOURCE_RESERVE_CU_1, 0xffffffff, 0x00000800,
+ mmSPI_RESOURCE_RESERVE_EN_CU_0, 0xffffffff, 0x00007FBF,
+};
+
+void xgpu_vi_init_golden_registers(struct amdgpu_device *adev)
+{
+ switch (adev->asic_type) {
+ case CHIP_FIJI:
+ amdgpu_program_register_sequence(adev,
+ xgpu_fiji_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(
+ xgpu_fiji_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ xgpu_fiji_golden_settings_a10,
+ (const u32)ARRAY_SIZE(
+ xgpu_fiji_golden_settings_a10));
+ amdgpu_program_register_sequence(adev,
+ xgpu_fiji_golden_common_all,
+ (const u32)ARRAY_SIZE(
+ xgpu_fiji_golden_common_all));
+ break;
+ case CHIP_TONGA:
+ amdgpu_program_register_sequence(adev,
+ xgpu_tonga_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(
+ xgpu_tonga_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ xgpu_tonga_golden_settings_a11,
+ (const u32)ARRAY_SIZE(
+ xgpu_tonga_golden_settings_a11));
+ amdgpu_program_register_sequence(adev,
+ xgpu_tonga_golden_common_all,
+ (const u32)ARRAY_SIZE(
+ xgpu_tonga_golden_common_all));
+ break;
+ default:
+ BUG_ON("Doesn't support chip type.\n");
+ break;
+ }
+}
+
+/*
+ * Mailbox communication between GPU hypervisor and VFs
+ */
+static void xgpu_vi_mailbox_send_ack(struct amdgpu_device *adev)
+{
+ u32 reg;
+
+ reg = RREG32(mmMAILBOX_CONTROL);
+ reg = REG_SET_FIELD(reg, MAILBOX_CONTROL, RCV_MSG_ACK, 1);
+ WREG32(mmMAILBOX_CONTROL, reg);
+}
+
+static void xgpu_vi_mailbox_set_valid(struct amdgpu_device *adev, bool val)
+{
+ u32 reg;
+
+ reg = RREG32(mmMAILBOX_CONTROL);
+ reg = REG_SET_FIELD(reg, MAILBOX_CONTROL,
+ TRN_MSG_VALID, val ? 1 : 0);
+ WREG32(mmMAILBOX_CONTROL, reg);
+}
+
+static void xgpu_vi_mailbox_trans_msg(struct amdgpu_device *adev,
+ enum idh_event event)
+{
+ u32 reg;
+
+ reg = RREG32(mmMAILBOX_MSGBUF_TRN_DW0);
+ reg = REG_SET_FIELD(reg, MAILBOX_MSGBUF_TRN_DW0,
+ MSGBUF_DATA, event);
+ WREG32(mmMAILBOX_MSGBUF_TRN_DW0, reg);
+
+ xgpu_vi_mailbox_set_valid(adev, true);
+}
+
+static int xgpu_vi_mailbox_rcv_msg(struct amdgpu_device *adev,
+ enum idh_event event)
+{
+ u32 reg;
+
+ reg = RREG32(mmMAILBOX_MSGBUF_RCV_DW0);
+ if (reg != event)
+ return -ENOENT;
+
+ /* send ack to PF */
+ xgpu_vi_mailbox_send_ack(adev);
+
+ return 0;
+}
+
+static int xgpu_vi_poll_ack(struct amdgpu_device *adev)
+{
+ int r = 0, timeout = VI_MAILBOX_TIMEDOUT;
+ u32 mask = REG_FIELD_MASK(MAILBOX_CONTROL, TRN_MSG_ACK);
+ u32 reg;
+
+ reg = RREG32(mmMAILBOX_CONTROL);
+ while (!(reg & mask)) {
+ if (timeout <= 0) {
+ pr_err("Doesn't get ack from pf.\n");
+ r = -ETIME;
+ break;
+ }
+ msleep(1);
+ timeout -= 1;
+
+ reg = RREG32(mmMAILBOX_CONTROL);
+ }
+
+ return r;
+}
+
+static int xgpu_vi_poll_msg(struct amdgpu_device *adev, enum idh_event event)
+{
+ int r = 0, timeout = VI_MAILBOX_TIMEDOUT;
+
+ r = xgpu_vi_mailbox_rcv_msg(adev, event);
+ while (r) {
+ if (timeout <= 0) {
+ pr_err("Doesn't get ack from pf.\n");
+ r = -ETIME;
+ break;
+ }
+ msleep(1);
+ timeout -= 1;
+
+ r = xgpu_vi_mailbox_rcv_msg(adev, event);
+ }
+
+ return r;
+}
+
+static int xgpu_vi_send_access_requests(struct amdgpu_device *adev,
+ enum idh_request request)
+{
+ int r;
+
+ xgpu_vi_mailbox_trans_msg(adev, request);
+
+ /* start to poll ack */
+ r = xgpu_vi_poll_ack(adev);
+ if (r)
+ return r;
+
+ xgpu_vi_mailbox_set_valid(adev, false);
+
+ /* start to check msg if request is idh_req_gpu_init_access */
+ if (request == IDH_REQ_GPU_INIT_ACCESS) {
+ r = xgpu_vi_poll_msg(adev, IDH_READY_TO_ACCESS_GPU);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static int xgpu_vi_request_reset(struct amdgpu_device *adev)
+{
+ return xgpu_vi_send_access_requests(adev, IDH_REQ_GPU_RESET_ACCESS);
+}
+
+static int xgpu_vi_request_full_gpu_access(struct amdgpu_device *adev,
+ bool init)
+{
+ enum idh_event event;
+
+ event = init ? IDH_REQ_GPU_INIT_ACCESS : IDH_REQ_GPU_FINI_ACCESS;
+ return xgpu_vi_send_access_requests(adev, event);
+}
+
+static int xgpu_vi_release_full_gpu_access(struct amdgpu_device *adev,
+ bool init)
+{
+ enum idh_event event;
+ int r = 0;
+
+ event = init ? IDH_REL_GPU_INIT_ACCESS : IDH_REL_GPU_FINI_ACCESS;
+ r = xgpu_vi_send_access_requests(adev, event);
+
+ return r;
+}
+
+/* add support mailbox interrupts */
+static int xgpu_vi_mailbox_ack_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ DRM_DEBUG("get ack intr and do nothing.\n");
+ return 0;
+}
+
+static int xgpu_vi_set_mailbox_ack_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ u32 tmp = RREG32(mmMAILBOX_INT_CNTL);
+
+ tmp = REG_SET_FIELD(tmp, MAILBOX_INT_CNTL, ACK_INT_EN,
+ (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0);
+ WREG32(mmMAILBOX_INT_CNTL, tmp);
+
+ return 0;
+}
+
+static void xgpu_vi_mailbox_flr_work(struct work_struct *work)
+{
+ struct amdgpu_virt *virt = container_of(work,
+ struct amdgpu_virt, flr_work.work);
+ struct amdgpu_device *adev = container_of(virt,
+ struct amdgpu_device, virt);
+ int r = 0;
+
+ r = xgpu_vi_poll_msg(adev, IDH_FLR_NOTIFICATION_CMPL);
+ if (r)
+ DRM_ERROR("failed to get flr cmpl msg from hypervior.\n");
+
+ /* TODO: need to restore gfx states */
+}
+
+static int xgpu_vi_set_mailbox_rcv_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ u32 tmp = RREG32(mmMAILBOX_INT_CNTL);
+
+ tmp = REG_SET_FIELD(tmp, MAILBOX_INT_CNTL, VALID_INT_EN,
+ (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0);
+ WREG32(mmMAILBOX_INT_CNTL, tmp);
+
+ return 0;
+}
+
+static int xgpu_vi_mailbox_rcv_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ int r;
+
+ adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME;
+ r = xgpu_vi_mailbox_rcv_msg(adev, IDH_FLR_NOTIFICATION);
+ /* do nothing for other msg */
+ if (r)
+ return 0;
+
+ /* TODO: need to save gfx states */
+ schedule_delayed_work(&adev->virt.flr_work,
+ msecs_to_jiffies(VI_MAILBOX_RESET_TIME));
+
+ return 0;
+}
+
+static const struct amdgpu_irq_src_funcs xgpu_vi_mailbox_ack_irq_funcs = {
+ .set = xgpu_vi_set_mailbox_ack_irq,
+ .process = xgpu_vi_mailbox_ack_irq,
+};
+
+static const struct amdgpu_irq_src_funcs xgpu_vi_mailbox_rcv_irq_funcs = {
+ .set = xgpu_vi_set_mailbox_rcv_irq,
+ .process = xgpu_vi_mailbox_rcv_irq,
+};
+
+void xgpu_vi_mailbox_set_irq_funcs(struct amdgpu_device *adev)
+{
+ adev->virt.ack_irq.num_types = 1;
+ adev->virt.ack_irq.funcs = &xgpu_vi_mailbox_ack_irq_funcs;
+ adev->virt.rcv_irq.num_types = 1;
+ adev->virt.rcv_irq.funcs = &xgpu_vi_mailbox_rcv_irq_funcs;
+}
+
+int xgpu_vi_mailbox_add_irq_id(struct amdgpu_device *adev)
+{
+ int r;
+
+ r = amdgpu_irq_add_id(adev, 135, &adev->virt.rcv_irq);
+ if (r)
+ return r;
+
+ r = amdgpu_irq_add_id(adev, 138, &adev->virt.ack_irq);
+ if (r) {
+ amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
+ return r;
+ }
+
+ return 0;
+}
+
+int xgpu_vi_mailbox_get_irq(struct amdgpu_device *adev)
+{
+ int r;
+
+ r = amdgpu_irq_get(adev, &adev->virt.rcv_irq, 0);
+ if (r)
+ return r;
+ r = amdgpu_irq_get(adev, &adev->virt.ack_irq, 0);
+ if (r) {
+ amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
+ return r;
+ }
+
+ INIT_DELAYED_WORK(&adev->virt.flr_work, xgpu_vi_mailbox_flr_work);
+
+ return 0;
+}
+
+void xgpu_vi_mailbox_put_irq(struct amdgpu_device *adev)
+{
+ cancel_delayed_work_sync(&adev->virt.flr_work);
+ amdgpu_irq_put(adev, &adev->virt.ack_irq, 0);
+ amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
+}
+
+const struct amdgpu_virt_ops xgpu_vi_virt_ops = {
+ .req_full_gpu = xgpu_vi_request_full_gpu_access,
+ .rel_full_gpu = xgpu_vi_release_full_gpu_access,
+ .reset_gpu = xgpu_vi_request_reset,
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.h
new file mode 100644
index 000000000000..fd6216efd2b0
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MXGPU_VI_H__
+#define __MXGPU_VI_H__
+
+#define VI_MAILBOX_TIMEDOUT 150
+#define VI_MAILBOX_RESET_TIME 12
+
+/* VI mailbox messages request */
+enum idh_request {
+ IDH_REQ_GPU_INIT_ACCESS = 1,
+ IDH_REL_GPU_INIT_ACCESS,
+ IDH_REQ_GPU_FINI_ACCESS,
+ IDH_REL_GPU_FINI_ACCESS,
+ IDH_REQ_GPU_RESET_ACCESS
+};
+
+/* VI mailbox messages data */
+enum idh_event {
+ IDH_CLR_MSG_BUF = 0,
+ IDH_READY_TO_ACCESS_GPU,
+ IDH_FLR_NOTIFICATION,
+ IDH_FLR_NOTIFICATION_CMPL,
+ IDH_EVENT_MAX
+};
+
+extern const struct amdgpu_virt_ops xgpu_vi_virt_ops;
+
+void xgpu_vi_init_golden_registers(struct amdgpu_device *adev);
+void xgpu_vi_mailbox_set_irq_funcs(struct amdgpu_device *adev);
+int xgpu_vi_mailbox_add_irq_id(struct amdgpu_device *adev);
+int xgpu_vi_mailbox_get_irq(struct amdgpu_device *adev);
+void xgpu_vi_mailbox_put_irq(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index fbe74a33899c..896be64b7013 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -701,7 +701,7 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[7] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP);
ib.length_dw = 8;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err1;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 1170a64a3184..31375bdde6f1 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -60,6 +60,8 @@ MODULE_FIRMWARE("amdgpu/polaris10_sdma.bin");
MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin");
MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin");
MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin");
static const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
@@ -206,6 +208,7 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev)
(const u32)ARRAY_SIZE(golden_settings_tonga_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
@@ -278,6 +281,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_CARRIZO:
chip_name = "carrizo";
break;
@@ -904,7 +910,7 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[7] = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP);
ib.length_dw = 8;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err1;
@@ -1527,6 +1533,22 @@ static int sdma_v3_0_set_powergating_state(void *handle,
return 0;
}
+static void sdma_v3_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ /* AMD_CG_SUPPORT_SDMA_MGCG */
+ data = RREG32(mmSDMA0_CLK_CTRL + sdma_offsets[0]);
+ if (!(data & SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK))
+ *flags |= AMD_CG_SUPPORT_SDMA_MGCG;
+
+ /* AMD_CG_SUPPORT_SDMA_LS */
+ data = RREG32(mmSDMA0_POWER_CNTL + sdma_offsets[0]);
+ if (data & SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK)
+ *flags |= AMD_CG_SUPPORT_SDMA_LS;
+}
+
static const struct amd_ip_funcs sdma_v3_0_ip_funcs = {
.name = "sdma_v3_0",
.early_init = sdma_v3_0_early_init,
@@ -1545,6 +1567,7 @@ static const struct amd_ip_funcs sdma_v3_0_ip_funcs = {
.soft_reset = sdma_v3_0_soft_reset,
.set_clockgating_state = sdma_v3_0_set_clockgating_state,
.set_powergating_state = sdma_v3_0_set_powergating_state,
+ .get_clockgating_state = sdma_v3_0_get_clockgating_state,
};
static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index c46b0159007d..da46992f7b18 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -32,7 +32,7 @@
#include "amdgpu_vce.h"
#include "atom.h"
#include "amdgpu_powerplay.h"
-#include "si/sid.h"
+#include "sid.h"
#include "si_ih.h"
#include "gfx_v6_0.h"
#include "gmc_v6_0.h"
@@ -40,337 +40,343 @@
#include "dce_v6_0.h"
#include "si.h"
#include "dce_virtual.h"
+#include "gca/gfx_6_0_d.h"
+#include "oss/oss_1_0_d.h"
+#include "gmc/gmc_6_0_d.h"
+#include "dce/dce_6_0_d.h"
+#include "uvd/uvd_4_0_d.h"
static const u32 tahiti_golden_registers[] =
{
- 0x17bc, 0x00000030, 0x00000011,
- 0x2684, 0x00010000, 0x00018208,
- 0x260c, 0xffffffff, 0x00000000,
- 0x260d, 0xf00fffff, 0x00000400,
- 0x260e, 0x0002021c, 0x00020200,
- 0x031e, 0x00000080, 0x00000000,
+ mmAZALIA_SCLK_CONTROL, 0x00000030, 0x00000011,
+ mmCB_HW_CONTROL, 0x00010000, 0x00018208,
+ mmDB_DEBUG, 0xffffffff, 0x00000000,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDB_DEBUG3, 0x0002021c, 0x00020200,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
0x340c, 0x000000c0, 0x00800040,
0x360c, 0x000000c0, 0x00800040,
- 0x16ec, 0x000000f0, 0x00000070,
- 0x16f0, 0x00200000, 0x50100000,
- 0x1c0c, 0x31000311, 0x00000011,
- 0x09df, 0x00000003, 0x000007ff,
- 0x0903, 0x000007ff, 0x00000000,
- 0x2285, 0xf000001f, 0x00000007,
- 0x22c9, 0xffffffff, 0x00ffffff,
- 0x22c4, 0x0000ff0f, 0x00000000,
- 0xa293, 0x07ffffff, 0x4e000000,
- 0xa0d4, 0x3f3f3fff, 0x2a00126a,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x00200000, 0x50100000,
+ mmDIG0_HDMI_CONTROL, 0x31000311, 0x00000011,
+ mmMC_ARB_WTM_CNTL_RD, 0x00000003, 0x000007ff,
+ mmMC_XPB_P2P_BAR_CFG, 0x000007ff, 0x00000000,
+ mmPA_CL_ENHANCE, 0xf000001f, 0x00000007,
+ mmPA_SC_FORCE_EOV_MAX_CNTS, 0xffffffff, 0x00ffffff,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmPA_SC_MODE_CNTL_1, 0x07ffffff, 0x4e000000,
+ mmPA_SC_RASTER_CONFIG, 0x3f3f3fff, 0x2a00126a,
0x000c, 0xffffffff, 0x0040,
0x000d, 0x00000040, 0x00004040,
- 0x2440, 0x07ffffff, 0x03000000,
- 0x23a2, 0x01ff1f3f, 0x00000000,
- 0x23a1, 0x01ff1f3f, 0x00000000,
- 0x2418, 0x0000007f, 0x00000020,
- 0x2542, 0x00010000, 0x00010000,
- 0x2b05, 0x00000200, 0x000002fb,
- 0x2b04, 0xffffffff, 0x0000543b,
- 0x2b03, 0xffffffff, 0xa9210876,
- 0x2234, 0xffffffff, 0x000fff40,
- 0x2235, 0x0000001f, 0x00000010,
- 0x0504, 0x20000000, 0x20fffed8,
- 0x0570, 0x000c0fc0, 0x000c0400,
- 0x052c, 0x0fffffff, 0xffffffff,
- 0x052d, 0x0fffffff, 0x0fffffff,
- 0x052e, 0x0fffffff, 0x0fffffff,
- 0x052f, 0x0fffffff, 0x0fffffff
+ mmSPI_CONFIG_CNTL, 0x07ffffff, 0x03000000,
+ mmSQ_DED_CNT, 0x01ff1f3f, 0x00000000,
+ mmSQ_SEC_CNT, 0x01ff1f3f, 0x00000000,
+ mmSX_DEBUG_1, 0x0000007f, 0x00000020,
+ mmTA_CNTL_AUX, 0x00010000, 0x00010000,
+ mmTCP_ADDR_CONFIG, 0x00000200, 0x000002fb,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x0000543b,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0xa9210876,
+ mmVGT_FIFO_DEPTHS, 0xffffffff, 0x000fff40,
+ mmVGT_GS_VERTEX_REUSE, 0x0000001f, 0x00000010,
+ mmVM_CONTEXT0_CNTL, 0x20000000, 0x20fffed8,
+ mmVM_L2_CG, 0x000c0fc0, 0x000c0400,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0xffffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
};
static const u32 tahiti_golden_registers2[] =
{
- 0x0319, 0x00000001, 0x00000001
+ mmMCIF_MEM_CONTROL, 0x00000001, 0x00000001,
};
static const u32 tahiti_golden_rlc_registers[] =
{
- 0x263e, 0xffffffff, 0x12011003,
- 0x3109, 0xffffffff, 0x00601005,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x12011003,
+ mmRLC_LB_PARAMS, 0xffffffff, 0x00601005,
0x311f, 0xffffffff, 0x10104040,
0x3122, 0xffffffff, 0x0100000a,
- 0x30c5, 0xffffffff, 0x00000800,
- 0x30c3, 0xffffffff, 0x800000f4,
- 0x3d2a, 0x00000008, 0x00000000
+ mmRLC_LB_CNTR_MAX, 0xffffffff, 0x00000800,
+ mmRLC_LB_CNTL, 0xffffffff, 0x800000f4,
+ mmUVD_CGC_GATE, 0x00000008, 0x00000000,
};
static const u32 pitcairn_golden_registers[] =
{
- 0x17bc, 0x00000030, 0x00000011,
- 0x2684, 0x00010000, 0x00018208,
- 0x260c, 0xffffffff, 0x00000000,
- 0x260d, 0xf00fffff, 0x00000400,
- 0x260e, 0x0002021c, 0x00020200,
- 0x031e, 0x00000080, 0x00000000,
+ mmAZALIA_SCLK_CONTROL, 0x00000030, 0x00000011,
+ mmCB_HW_CONTROL, 0x00010000, 0x00018208,
+ mmDB_DEBUG, 0xffffffff, 0x00000000,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDB_DEBUG3, 0x0002021c, 0x00020200,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
0x340c, 0x000300c0, 0x00800040,
0x360c, 0x000300c0, 0x00800040,
- 0x16ec, 0x000000f0, 0x00000070,
- 0x16f0, 0x00200000, 0x50100000,
- 0x1c0c, 0x31000311, 0x00000011,
- 0x0ab9, 0x00073ffe, 0x000022a2,
- 0x0903, 0x000007ff, 0x00000000,
- 0x2285, 0xf000001f, 0x00000007,
- 0x22c9, 0xffffffff, 0x00ffffff,
- 0x22c4, 0x0000ff0f, 0x00000000,
- 0xa293, 0x07ffffff, 0x4e000000,
- 0xa0d4, 0x3f3f3fff, 0x2a00126a,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x00200000, 0x50100000,
+ mmDIG0_HDMI_CONTROL, 0x31000311, 0x00000011,
+ mmMC_SEQ_PMG_PG_HWCNTL, 0x00073ffe, 0x000022a2,
+ mmMC_XPB_P2P_BAR_CFG, 0x000007ff, 0x00000000,
+ mmPA_CL_ENHANCE, 0xf000001f, 0x00000007,
+ mmPA_SC_FORCE_EOV_MAX_CNTS, 0xffffffff, 0x00ffffff,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmPA_SC_MODE_CNTL_1, 0x07ffffff, 0x4e000000,
+ mmPA_SC_RASTER_CONFIG, 0x3f3f3fff, 0x2a00126a,
0x000c, 0xffffffff, 0x0040,
0x000d, 0x00000040, 0x00004040,
- 0x2440, 0x07ffffff, 0x03000000,
- 0x2418, 0x0000007f, 0x00000020,
- 0x2542, 0x00010000, 0x00010000,
- 0x2b05, 0x000003ff, 0x000000f7,
- 0x2b04, 0xffffffff, 0x00000000,
- 0x2b03, 0xffffffff, 0x32761054,
- 0x2235, 0x0000001f, 0x00000010,
- 0x0570, 0x000c0fc0, 0x000c0400,
- 0x052c, 0x0fffffff, 0xffffffff,
- 0x052d, 0x0fffffff, 0x0fffffff,
- 0x052e, 0x0fffffff, 0x0fffffff,
- 0x052f, 0x0fffffff, 0x0fffffff
+ mmSPI_CONFIG_CNTL, 0x07ffffff, 0x03000000,
+ mmSX_DEBUG_1, 0x0000007f, 0x00000020,
+ mmTA_CNTL_AUX, 0x00010000, 0x00010000,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f7,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0x32761054,
+ mmVGT_GS_VERTEX_REUSE, 0x0000001f, 0x00000010,
+ mmVM_L2_CG, 0x000c0fc0, 0x000c0400,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0xffffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
};
static const u32 pitcairn_golden_rlc_registers[] =
{
- 0x263e, 0xffffffff, 0x12011003,
- 0x3109, 0xffffffff, 0x00601004,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x12011003,
+ mmRLC_LB_PARAMS, 0xffffffff, 0x00601004,
0x311f, 0xffffffff, 0x10102020,
0x3122, 0xffffffff, 0x01000020,
- 0x30c5, 0xffffffff, 0x00000800,
- 0x30c3, 0xffffffff, 0x800000a4
+ mmRLC_LB_CNTR_MAX, 0xffffffff, 0x00000800,
+ mmRLC_LB_CNTL, 0xffffffff, 0x800000a4,
};
static const u32 verde_pg_init[] =
{
- 0x0d4f, 0xffffffff, 0x40000,
- 0x0d4e, 0xffffffff, 0x200010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x7007,
- 0x0d4e, 0xffffffff, 0x300010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x400000,
- 0x0d4e, 0xffffffff, 0x100010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x120200,
- 0x0d4e, 0xffffffff, 0x500010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x1e1e16,
- 0x0d4e, 0xffffffff, 0x600010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x171f1e,
- 0x0d4e, 0xffffffff, 0x700010ff,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4f, 0xffffffff, 0x0,
- 0x0d4e, 0xffffffff, 0x9ff,
- 0x0d40, 0xffffffff, 0x0,
- 0x0d41, 0xffffffff, 0x10000800,
- 0x0d41, 0xffffffff, 0xf,
- 0x0d41, 0xffffffff, 0xf,
- 0x0d40, 0xffffffff, 0x4,
- 0x0d41, 0xffffffff, 0x1000051e,
- 0x0d41, 0xffffffff, 0xffff,
- 0x0d41, 0xffffffff, 0xffff,
- 0x0d40, 0xffffffff, 0x8,
- 0x0d41, 0xffffffff, 0x80500,
- 0x0d40, 0xffffffff, 0x12,
- 0x0d41, 0xffffffff, 0x9050c,
- 0x0d40, 0xffffffff, 0x1d,
- 0x0d41, 0xffffffff, 0xb052c,
- 0x0d40, 0xffffffff, 0x2a,
- 0x0d41, 0xffffffff, 0x1053e,
- 0x0d40, 0xffffffff, 0x2d,
- 0x0d41, 0xffffffff, 0x10546,
- 0x0d40, 0xffffffff, 0x30,
- 0x0d41, 0xffffffff, 0xa054e,
- 0x0d40, 0xffffffff, 0x3c,
- 0x0d41, 0xffffffff, 0x1055f,
- 0x0d40, 0xffffffff, 0x3f,
- 0x0d41, 0xffffffff, 0x10567,
- 0x0d40, 0xffffffff, 0x42,
- 0x0d41, 0xffffffff, 0x1056f,
- 0x0d40, 0xffffffff, 0x45,
- 0x0d41, 0xffffffff, 0x10572,
- 0x0d40, 0xffffffff, 0x48,
- 0x0d41, 0xffffffff, 0x20575,
- 0x0d40, 0xffffffff, 0x4c,
- 0x0d41, 0xffffffff, 0x190801,
- 0x0d40, 0xffffffff, 0x67,
- 0x0d41, 0xffffffff, 0x1082a,
- 0x0d40, 0xffffffff, 0x6a,
- 0x0d41, 0xffffffff, 0x1b082d,
- 0x0d40, 0xffffffff, 0x87,
- 0x0d41, 0xffffffff, 0x310851,
- 0x0d40, 0xffffffff, 0xba,
- 0x0d41, 0xffffffff, 0x891,
- 0x0d40, 0xffffffff, 0xbc,
- 0x0d41, 0xffffffff, 0x893,
- 0x0d40, 0xffffffff, 0xbe,
- 0x0d41, 0xffffffff, 0x20895,
- 0x0d40, 0xffffffff, 0xc2,
- 0x0d41, 0xffffffff, 0x20899,
- 0x0d40, 0xffffffff, 0xc6,
- 0x0d41, 0xffffffff, 0x2089d,
- 0x0d40, 0xffffffff, 0xca,
- 0x0d41, 0xffffffff, 0x8a1,
- 0x0d40, 0xffffffff, 0xcc,
- 0x0d41, 0xffffffff, 0x8a3,
- 0x0d40, 0xffffffff, 0xce,
- 0x0d41, 0xffffffff, 0x308a5,
- 0x0d40, 0xffffffff, 0xd3,
- 0x0d41, 0xffffffff, 0x6d08cd,
- 0x0d40, 0xffffffff, 0x142,
- 0x0d41, 0xffffffff, 0x2000095a,
- 0x0d41, 0xffffffff, 0x1,
- 0x0d40, 0xffffffff, 0x144,
- 0x0d41, 0xffffffff, 0x301f095b,
- 0x0d40, 0xffffffff, 0x165,
- 0x0d41, 0xffffffff, 0xc094d,
- 0x0d40, 0xffffffff, 0x173,
- 0x0d41, 0xffffffff, 0xf096d,
- 0x0d40, 0xffffffff, 0x184,
- 0x0d41, 0xffffffff, 0x15097f,
- 0x0d40, 0xffffffff, 0x19b,
- 0x0d41, 0xffffffff, 0xc0998,
- 0x0d40, 0xffffffff, 0x1a9,
- 0x0d41, 0xffffffff, 0x409a7,
- 0x0d40, 0xffffffff, 0x1af,
- 0x0d41, 0xffffffff, 0xcdc,
- 0x0d40, 0xffffffff, 0x1b1,
- 0x0d41, 0xffffffff, 0x800,
- 0x0d42, 0xffffffff, 0x6c9b2000,
- 0x0d44, 0xfc00, 0x2000,
- 0x0d51, 0xffffffff, 0xfc0,
- 0x0a35, 0x00000100, 0x100
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x40000,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x200010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x7007,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x300010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x400000,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x100010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x120200,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x500010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x1e1e16,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x600010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x171f1e,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x700010ff,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_WRITE, 0xffffffff, 0x0,
+ mmGMCON_PGFSM_CONFIG, 0xffffffff, 0x9ff,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x0,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x10000800,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xf,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xf,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x4,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1000051e,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xffff,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xffff,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x8,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x80500,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x12,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x9050c,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x1d,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xb052c,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x2a,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1053e,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x2d,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x10546,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x30,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xa054e,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x3c,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1055f,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x3f,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x10567,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x42,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1056f,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x45,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x10572,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x48,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x20575,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x4c,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x190801,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x67,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1082a,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x6a,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1b082d,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x87,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x310851,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xba,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x891,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xbc,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x893,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xbe,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x20895,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xc2,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x20899,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xc6,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x2089d,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xca,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x8a1,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xcc,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x8a3,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xce,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x308a5,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0xd3,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x6d08cd,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x142,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x2000095a,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x1,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x144,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x301f095b,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x165,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xc094d,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x173,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xf096d,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x184,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x15097f,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x19b,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xc0998,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x1a9,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x409a7,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x1af,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0xcdc,
+ mmGMCON_RENG_RAM_INDEX, 0xffffffff, 0x1b1,
+ mmGMCON_RENG_RAM_DATA, 0xffffffff, 0x800,
+ mmGMCON_RENG_EXECUTE, 0xffffffff, 0x6c9b2000,
+ mmGMCON_MISC2, 0xfc00, 0x2000,
+ mmGMCON_MISC3, 0xffffffff, 0xfc0,
+ mmMC_PMG_AUTO_CFG, 0x00000100, 0x100,
};
static const u32 verde_golden_rlc_registers[] =
{
- 0x263e, 0xffffffff, 0x02010002,
- 0x3109, 0xffffffff, 0x033f1005,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x02010002,
+ mmRLC_LB_PARAMS, 0xffffffff, 0x033f1005,
0x311f, 0xffffffff, 0x10808020,
0x3122, 0xffffffff, 0x00800008,
- 0x30c5, 0xffffffff, 0x00001000,
- 0x30c3, 0xffffffff, 0x80010014
+ mmRLC_LB_CNTR_MAX, 0xffffffff, 0x00001000,
+ mmRLC_LB_CNTL, 0xffffffff, 0x80010014,
};
static const u32 verde_golden_registers[] =
{
- 0x17bc, 0x00000030, 0x00000011,
- 0x2684, 0x00010000, 0x00018208,
- 0x260c, 0xffffffff, 0x00000000,
- 0x260d, 0xf00fffff, 0x00000400,
- 0x260e, 0x0002021c, 0x00020200,
- 0x031e, 0x00000080, 0x00000000,
+ mmAZALIA_SCLK_CONTROL, 0x00000030, 0x00000011,
+ mmCB_HW_CONTROL, 0x00010000, 0x00018208,
+ mmDB_DEBUG, 0xffffffff, 0x00000000,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDB_DEBUG3, 0x0002021c, 0x00020200,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
0x340c, 0x000300c0, 0x00800040,
0x360c, 0x000300c0, 0x00800040,
- 0x16ec, 0x000000f0, 0x00000070,
- 0x16f0, 0x00200000, 0x50100000,
- 0x1c0c, 0x31000311, 0x00000011,
- 0x0ab9, 0x00073ffe, 0x000022a2,
- 0x0903, 0x000007ff, 0x00000000,
- 0x2285, 0xf000001f, 0x00000007,
- 0x22c9, 0xffffffff, 0x00ffffff,
- 0x22c4, 0x0000ff0f, 0x00000000,
- 0xa293, 0x07ffffff, 0x4e000000,
- 0xa0d4, 0x3f3f3fff, 0x0000124a,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x00200000, 0x50100000,
+ mmDIG0_HDMI_CONTROL, 0x31000311, 0x00000011,
+ mmMC_SEQ_PMG_PG_HWCNTL, 0x00073ffe, 0x000022a2,
+ mmMC_XPB_P2P_BAR_CFG, 0x000007ff, 0x00000000,
+ mmPA_CL_ENHANCE, 0xf000001f, 0x00000007,
+ mmPA_SC_FORCE_EOV_MAX_CNTS, 0xffffffff, 0x00ffffff,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmPA_SC_MODE_CNTL_1, 0x07ffffff, 0x4e000000,
+ mmPA_SC_RASTER_CONFIG, 0x3f3f3fff, 0x0000124a,
0x000c, 0xffffffff, 0x0040,
0x000d, 0x00000040, 0x00004040,
- 0x2440, 0x07ffffff, 0x03000000,
- 0x23a2, 0x01ff1f3f, 0x00000000,
- 0x23a1, 0x01ff1f3f, 0x00000000,
- 0x2418, 0x0000007f, 0x00000020,
- 0x2542, 0x00010000, 0x00010000,
- 0x2b05, 0x000003ff, 0x00000003,
- 0x2b04, 0xffffffff, 0x00000000,
- 0x2b03, 0xffffffff, 0x00001032,
- 0x2235, 0x0000001f, 0x00000010,
- 0x0570, 0x000c0fc0, 0x000c0400,
- 0x052c, 0x0fffffff, 0xffffffff,
- 0x052d, 0x0fffffff, 0x0fffffff,
- 0x052e, 0x0fffffff, 0x0fffffff,
- 0x052f, 0x0fffffff, 0x0fffffff
+ mmSPI_CONFIG_CNTL, 0x07ffffff, 0x03000000,
+ mmSQ_DED_CNT, 0x01ff1f3f, 0x00000000,
+ mmSQ_SEC_CNT, 0x01ff1f3f, 0x00000000,
+ mmSX_DEBUG_1, 0x0000007f, 0x00000020,
+ mmTA_CNTL_AUX, 0x00010000, 0x00010000,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x00000003,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0x00001032,
+ mmVGT_GS_VERTEX_REUSE, 0x0000001f, 0x00000010,
+ mmVM_L2_CG, 0x000c0fc0, 0x000c0400,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0xffffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
};
static const u32 oland_golden_registers[] =
{
- 0x17bc, 0x00000030, 0x00000011,
- 0x2684, 0x00010000, 0x00018208,
- 0x260c, 0xffffffff, 0x00000000,
- 0x260d, 0xf00fffff, 0x00000400,
- 0x260e, 0x0002021c, 0x00020200,
- 0x031e, 0x00000080, 0x00000000,
+ mmAZALIA_SCLK_CONTROL, 0x00000030, 0x00000011,
+ mmCB_HW_CONTROL, 0x00010000, 0x00018208,
+ mmDB_DEBUG, 0xffffffff, 0x00000000,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDB_DEBUG3, 0x0002021c, 0x00020200,
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
0x340c, 0x000300c0, 0x00800040,
0x360c, 0x000300c0, 0x00800040,
- 0x16ec, 0x000000f0, 0x00000070,
- 0x16f0, 0x00200000, 0x50100000,
- 0x1c0c, 0x31000311, 0x00000011,
- 0x0ab9, 0x00073ffe, 0x000022a2,
- 0x0903, 0x000007ff, 0x00000000,
- 0x2285, 0xf000001f, 0x00000007,
- 0x22c9, 0xffffffff, 0x00ffffff,
- 0x22c4, 0x0000ff0f, 0x00000000,
- 0xa293, 0x07ffffff, 0x4e000000,
- 0xa0d4, 0x3f3f3fff, 0x00000082,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x00200000, 0x50100000,
+ mmDIG0_HDMI_CONTROL, 0x31000311, 0x00000011,
+ mmMC_SEQ_PMG_PG_HWCNTL, 0x00073ffe, 0x000022a2,
+ mmMC_XPB_P2P_BAR_CFG, 0x000007ff, 0x00000000,
+ mmPA_CL_ENHANCE, 0xf000001f, 0x00000007,
+ mmPA_SC_FORCE_EOV_MAX_CNTS, 0xffffffff, 0x00ffffff,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmPA_SC_MODE_CNTL_1, 0x07ffffff, 0x4e000000,
+ mmPA_SC_RASTER_CONFIG, 0x3f3f3fff, 0x00000082,
0x000c, 0xffffffff, 0x0040,
0x000d, 0x00000040, 0x00004040,
- 0x2440, 0x07ffffff, 0x03000000,
- 0x2418, 0x0000007f, 0x00000020,
- 0x2542, 0x00010000, 0x00010000,
- 0x2b05, 0x000003ff, 0x000000f3,
- 0x2b04, 0xffffffff, 0x00000000,
- 0x2b03, 0xffffffff, 0x00003210,
- 0x2235, 0x0000001f, 0x00000010,
- 0x0570, 0x000c0fc0, 0x000c0400,
- 0x052c, 0x0fffffff, 0xffffffff,
- 0x052d, 0x0fffffff, 0x0fffffff,
- 0x052e, 0x0fffffff, 0x0fffffff,
- 0x052f, 0x0fffffff, 0x0fffffff
+ mmSPI_CONFIG_CNTL, 0x07ffffff, 0x03000000,
+ mmSX_DEBUG_1, 0x0000007f, 0x00000020,
+ mmTA_CNTL_AUX, 0x00010000, 0x00010000,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f3,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0x00003210,
+ mmVGT_GS_VERTEX_REUSE, 0x0000001f, 0x00000010,
+ mmVM_L2_CG, 0x000c0fc0, 0x000c0400,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0xffffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+
};
static const u32 oland_golden_rlc_registers[] =
{
- 0x263e, 0xffffffff, 0x02010002,
- 0x3109, 0xffffffff, 0x00601005,
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x02010002,
+ mmRLC_LB_PARAMS, 0xffffffff, 0x00601005,
0x311f, 0xffffffff, 0x10104040,
0x3122, 0xffffffff, 0x0100000a,
- 0x30c5, 0xffffffff, 0x00000800,
- 0x30c3, 0xffffffff, 0x800000f4
+ mmRLC_LB_CNTR_MAX, 0xffffffff, 0x00000800,
+ mmRLC_LB_CNTL, 0xffffffff, 0x800000f4,
};
static const u32 hainan_golden_registers[] =
{
0x17bc, 0x00000030, 0x00000011,
- 0x2684, 0x00010000, 0x00018208,
- 0x260c, 0xffffffff, 0x00000000,
- 0x260d, 0xf00fffff, 0x00000400,
- 0x260e, 0x0002021c, 0x00020200,
+ mmCB_HW_CONTROL, 0x00010000, 0x00018208,
+ mmDB_DEBUG, 0xffffffff, 0x00000000,
+ mmDB_DEBUG2, 0xf00fffff, 0x00000400,
+ mmDB_DEBUG3, 0x0002021c, 0x00020200,
0x031e, 0x00000080, 0x00000000,
0x3430, 0xff000fff, 0x00000100,
0x340c, 0x000300c0, 0x00800040,
@@ -379,63 +385,63 @@ static const u32 hainan_golden_registers[] =
0x16ec, 0x000000f0, 0x00000070,
0x16f0, 0x00200000, 0x50100000,
0x1c0c, 0x31000311, 0x00000011,
- 0x0ab9, 0x00073ffe, 0x000022a2,
- 0x0903, 0x000007ff, 0x00000000,
- 0x2285, 0xf000001f, 0x00000007,
- 0x22c9, 0xffffffff, 0x00ffffff,
- 0x22c4, 0x0000ff0f, 0x00000000,
- 0xa293, 0x07ffffff, 0x4e000000,
- 0xa0d4, 0x3f3f3fff, 0x00000000,
+ mmMC_SEQ_PMG_PG_HWCNTL, 0x00073ffe, 0x000022a2,
+ mmMC_XPB_P2P_BAR_CFG, 0x000007ff, 0x00000000,
+ mmPA_CL_ENHANCE, 0xf000001f, 0x00000007,
+ mmPA_SC_FORCE_EOV_MAX_CNTS, 0xffffffff, 0x00ffffff,
+ mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+ mmPA_SC_MODE_CNTL_1, 0x07ffffff, 0x4e000000,
+ mmPA_SC_RASTER_CONFIG, 0x3f3f3fff, 0x00000000,
0x000c, 0xffffffff, 0x0040,
0x000d, 0x00000040, 0x00004040,
- 0x2440, 0x03e00000, 0x03600000,
- 0x2418, 0x0000007f, 0x00000020,
- 0x2542, 0x00010000, 0x00010000,
- 0x2b05, 0x000003ff, 0x000000f1,
- 0x2b04, 0xffffffff, 0x00000000,
- 0x2b03, 0xffffffff, 0x00003210,
- 0x2235, 0x0000001f, 0x00000010,
- 0x0570, 0x000c0fc0, 0x000c0400,
- 0x052c, 0x0fffffff, 0xffffffff,
- 0x052d, 0x0fffffff, 0x0fffffff,
- 0x052e, 0x0fffffff, 0x0fffffff,
- 0x052f, 0x0fffffff, 0x0fffffff
+ mmSPI_CONFIG_CNTL, 0x03e00000, 0x03600000,
+ mmSX_DEBUG_1, 0x0000007f, 0x00000020,
+ mmTA_CNTL_AUX, 0x00010000, 0x00010000,
+ mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f1,
+ mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000,
+ mmTCP_CHAN_STEER_LO, 0xffffffff, 0x00003210,
+ mmVGT_GS_VERTEX_REUSE, 0x0000001f, 0x00000010,
+ mmVM_L2_CG, 0x000c0fc0, 0x000c0400,
+ mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0xffffffff,
+ mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+ mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
};
static const u32 hainan_golden_registers2[] =
{
- 0x263e, 0xffffffff, 0x2011003
+ mmGB_ADDR_CONFIG, 0xffffffff, 0x2011003,
};
static const u32 tahiti_mgcg_cgcg_init[] =
{
- 0x3100, 0xffffffff, 0xfffffffc,
- 0x200b, 0xffffffff, 0xe0000000,
- 0x2698, 0xffffffff, 0x00000100,
- 0x24a9, 0xffffffff, 0x00000100,
- 0x3059, 0xffffffff, 0x00000100,
- 0x25dd, 0xffffffff, 0x00000100,
- 0x2261, 0xffffffff, 0x06000100,
- 0x2286, 0xffffffff, 0x00000100,
- 0x24a8, 0xffffffff, 0x00000100,
- 0x30e0, 0xffffffff, 0x00000100,
- 0x22ca, 0xffffffff, 0x00000100,
- 0x2451, 0xffffffff, 0x00000100,
- 0x2362, 0xffffffff, 0x00000100,
- 0x2363, 0xffffffff, 0x00000100,
- 0x240c, 0xffffffff, 0x00000100,
- 0x240d, 0xffffffff, 0x00000100,
- 0x240e, 0xffffffff, 0x00000100,
- 0x240f, 0xffffffff, 0x00000100,
- 0x2b60, 0xffffffff, 0x00000100,
- 0x2b15, 0xffffffff, 0x00000100,
- 0x225f, 0xffffffff, 0x06000100,
- 0x261a, 0xffffffff, 0x00000100,
- 0x2544, 0xffffffff, 0x00000100,
- 0x2bc1, 0xffffffff, 0x00000100,
- 0x2b81, 0xffffffff, 0x00000100,
- 0x2527, 0xffffffff, 0x00000100,
- 0x200b, 0xffffffff, 0xe0000000,
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xfffffffc,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
0x2458, 0xffffffff, 0x00010000,
0x2459, 0xffffffff, 0x00030002,
0x245a, 0xffffffff, 0x00040007,
@@ -516,55 +522,55 @@ static const u32 tahiti_mgcg_cgcg_init[] =
0x24a5, 0xffffffff, 0x00000015,
0x24a6, 0xffffffff, 0x00140013,
0x24a7, 0xffffffff, 0x00170016,
- 0x2454, 0xffffffff, 0x96940200,
- 0x21c2, 0xffffffff, 0x00900100,
- 0x311e, 0xffffffff, 0x00000080,
- 0x3101, 0xffffffff, 0x0020003f,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_GCPM_GENERAL_3, 0xffffffff, 0x00000080,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003f,
0x000c, 0xffffffff, 0x0000001c,
0x000d, 0x000f0000, 0x000f0000,
0x0583, 0xffffffff, 0x00000100,
- 0x0409, 0xffffffff, 0x00000100,
- 0x040b, 0x00000101, 0x00000000,
- 0x082a, 0xffffffff, 0x00000104,
- 0x0993, 0x000c0000, 0x000c0000,
- 0x0992, 0x000c0000, 0x000c0000,
- 0x1579, 0xff000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmMC_CITF_MISC_WR_CG, 0x000c0000, 0x000c0000,
+ mmMC_CITF_MISC_RD_CG, 0x000c0000, 0x000c0000,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
0x157a, 0x00000001, 0x00000001,
- 0x0bd4, 0x00000001, 0x00000001,
- 0x0c33, 0xc0000fff, 0x00000104,
- 0x3079, 0x00000001, 0x00000001,
+ mmHDP_MEM_POWER_LS, 0x00000001, 0x00000001,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
0x3430, 0xfffffff0, 0x00000100,
- 0x3630, 0xfffffff0, 0x00000100
+ 0x3630, 0xfffffff0, 0x00000100,
};
static const u32 pitcairn_mgcg_cgcg_init[] =
{
- 0x3100, 0xffffffff, 0xfffffffc,
- 0x200b, 0xffffffff, 0xe0000000,
- 0x2698, 0xffffffff, 0x00000100,
- 0x24a9, 0xffffffff, 0x00000100,
- 0x3059, 0xffffffff, 0x00000100,
- 0x25dd, 0xffffffff, 0x00000100,
- 0x2261, 0xffffffff, 0x06000100,
- 0x2286, 0xffffffff, 0x00000100,
- 0x24a8, 0xffffffff, 0x00000100,
- 0x30e0, 0xffffffff, 0x00000100,
- 0x22ca, 0xffffffff, 0x00000100,
- 0x2451, 0xffffffff, 0x00000100,
- 0x2362, 0xffffffff, 0x00000100,
- 0x2363, 0xffffffff, 0x00000100,
- 0x240c, 0xffffffff, 0x00000100,
- 0x240d, 0xffffffff, 0x00000100,
- 0x240e, 0xffffffff, 0x00000100,
- 0x240f, 0xffffffff, 0x00000100,
- 0x2b60, 0xffffffff, 0x00000100,
- 0x2b15, 0xffffffff, 0x00000100,
- 0x225f, 0xffffffff, 0x06000100,
- 0x261a, 0xffffffff, 0x00000100,
- 0x2544, 0xffffffff, 0x00000100,
- 0x2bc1, 0xffffffff, 0x00000100,
- 0x2b81, 0xffffffff, 0x00000100,
- 0x2527, 0xffffffff, 0x00000100,
- 0x200b, 0xffffffff, 0xe0000000,
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xfffffffc,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
0x2458, 0xffffffff, 0x00010000,
0x2459, 0xffffffff, 0x00030002,
0x245a, 0xffffffff, 0x00040007,
@@ -615,53 +621,54 @@ static const u32 pitcairn_mgcg_cgcg_init[] =
0x2496, 0xffffffff, 0x00100013,
0x2497, 0xffffffff, 0x00120011,
0x2498, 0xffffffff, 0x00150014,
- 0x2454, 0xffffffff, 0x96940200,
- 0x21c2, 0xffffffff, 0x00900100,
- 0x311e, 0xffffffff, 0x00000080,
- 0x3101, 0xffffffff, 0x0020003f,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_GCPM_GENERAL_3, 0xffffffff, 0x00000080,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003f,
0x000c, 0xffffffff, 0x0000001c,
0x000d, 0x000f0000, 0x000f0000,
0x0583, 0xffffffff, 0x00000100,
- 0x0409, 0xffffffff, 0x00000100,
- 0x040b, 0x00000101, 0x00000000,
- 0x082a, 0xffffffff, 0x00000104,
- 0x1579, 0xff000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
0x157a, 0x00000001, 0x00000001,
- 0x0bd4, 0x00000001, 0x00000001,
- 0x0c33, 0xc0000fff, 0x00000104,
- 0x3079, 0x00000001, 0x00000001,
+ mmHDP_MEM_POWER_LS, 0x00000001, 0x00000001,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
0x3430, 0xfffffff0, 0x00000100,
- 0x3630, 0xfffffff0, 0x00000100
+ 0x3630, 0xfffffff0, 0x00000100,
};
+
static const u32 verde_mgcg_cgcg_init[] =
{
- 0x3100, 0xffffffff, 0xfffffffc,
- 0x200b, 0xffffffff, 0xe0000000,
- 0x2698, 0xffffffff, 0x00000100,
- 0x24a9, 0xffffffff, 0x00000100,
- 0x3059, 0xffffffff, 0x00000100,
- 0x25dd, 0xffffffff, 0x00000100,
- 0x2261, 0xffffffff, 0x06000100,
- 0x2286, 0xffffffff, 0x00000100,
- 0x24a8, 0xffffffff, 0x00000100,
- 0x30e0, 0xffffffff, 0x00000100,
- 0x22ca, 0xffffffff, 0x00000100,
- 0x2451, 0xffffffff, 0x00000100,
- 0x2362, 0xffffffff, 0x00000100,
- 0x2363, 0xffffffff, 0x00000100,
- 0x240c, 0xffffffff, 0x00000100,
- 0x240d, 0xffffffff, 0x00000100,
- 0x240e, 0xffffffff, 0x00000100,
- 0x240f, 0xffffffff, 0x00000100,
- 0x2b60, 0xffffffff, 0x00000100,
- 0x2b15, 0xffffffff, 0x00000100,
- 0x225f, 0xffffffff, 0x06000100,
- 0x261a, 0xffffffff, 0x00000100,
- 0x2544, 0xffffffff, 0x00000100,
- 0x2bc1, 0xffffffff, 0x00000100,
- 0x2b81, 0xffffffff, 0x00000100,
- 0x2527, 0xffffffff, 0x00000100,
- 0x200b, 0xffffffff, 0xe0000000,
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xfffffffc,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
0x2458, 0xffffffff, 0x00010000,
0x2459, 0xffffffff, 0x00030002,
0x245a, 0xffffffff, 0x00040007,
@@ -712,55 +719,56 @@ static const u32 verde_mgcg_cgcg_init[] =
0x2496, 0xffffffff, 0x00100013,
0x2497, 0xffffffff, 0x00120011,
0x2498, 0xffffffff, 0x00150014,
- 0x2454, 0xffffffff, 0x96940200,
- 0x21c2, 0xffffffff, 0x00900100,
- 0x311e, 0xffffffff, 0x00000080,
- 0x3101, 0xffffffff, 0x0020003f,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_GCPM_GENERAL_3, 0xffffffff, 0x00000080,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003f,
0x000c, 0xffffffff, 0x0000001c,
0x000d, 0x000f0000, 0x000f0000,
0x0583, 0xffffffff, 0x00000100,
- 0x0409, 0xffffffff, 0x00000100,
- 0x040b, 0x00000101, 0x00000000,
- 0x082a, 0xffffffff, 0x00000104,
- 0x0993, 0x000c0000, 0x000c0000,
- 0x0992, 0x000c0000, 0x000c0000,
- 0x1579, 0xff000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmMC_CITF_MISC_WR_CG, 0x000c0000, 0x000c0000,
+ mmMC_CITF_MISC_RD_CG, 0x000c0000, 0x000c0000,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
0x157a, 0x00000001, 0x00000001,
- 0x0bd4, 0x00000001, 0x00000001,
- 0x0c33, 0xc0000fff, 0x00000104,
- 0x3079, 0x00000001, 0x00000001,
+ mmHDP_MEM_POWER_LS, 0x00000001, 0x00000001,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
0x3430, 0xfffffff0, 0x00000100,
- 0x3630, 0xfffffff0, 0x00000100
+ 0x3630, 0xfffffff0, 0x00000100,
};
+
static const u32 oland_mgcg_cgcg_init[] =
{
- 0x3100, 0xffffffff, 0xfffffffc,
- 0x200b, 0xffffffff, 0xe0000000,
- 0x2698, 0xffffffff, 0x00000100,
- 0x24a9, 0xffffffff, 0x00000100,
- 0x3059, 0xffffffff, 0x00000100,
- 0x25dd, 0xffffffff, 0x00000100,
- 0x2261, 0xffffffff, 0x06000100,
- 0x2286, 0xffffffff, 0x00000100,
- 0x24a8, 0xffffffff, 0x00000100,
- 0x30e0, 0xffffffff, 0x00000100,
- 0x22ca, 0xffffffff, 0x00000100,
- 0x2451, 0xffffffff, 0x00000100,
- 0x2362, 0xffffffff, 0x00000100,
- 0x2363, 0xffffffff, 0x00000100,
- 0x240c, 0xffffffff, 0x00000100,
- 0x240d, 0xffffffff, 0x00000100,
- 0x240e, 0xffffffff, 0x00000100,
- 0x240f, 0xffffffff, 0x00000100,
- 0x2b60, 0xffffffff, 0x00000100,
- 0x2b15, 0xffffffff, 0x00000100,
- 0x225f, 0xffffffff, 0x06000100,
- 0x261a, 0xffffffff, 0x00000100,
- 0x2544, 0xffffffff, 0x00000100,
- 0x2bc1, 0xffffffff, 0x00000100,
- 0x2b81, 0xffffffff, 0x00000100,
- 0x2527, 0xffffffff, 0x00000100,
- 0x200b, 0xffffffff, 0xe0000000,
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xfffffffc,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
0x2458, 0xffffffff, 0x00010000,
0x2459, 0xffffffff, 0x00030002,
0x245a, 0xffffffff, 0x00040007,
@@ -791,55 +799,56 @@ static const u32 oland_mgcg_cgcg_init[] =
0x2473, 0xffffffff, 0x0000000b,
0x2474, 0xffffffff, 0x000a0009,
0x2475, 0xffffffff, 0x000d000c,
- 0x2454, 0xffffffff, 0x96940200,
- 0x21c2, 0xffffffff, 0x00900100,
- 0x311e, 0xffffffff, 0x00000080,
- 0x3101, 0xffffffff, 0x0020003f,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_GCPM_GENERAL_3, 0xffffffff, 0x00000080,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003f,
0x000c, 0xffffffff, 0x0000001c,
0x000d, 0x000f0000, 0x000f0000,
0x0583, 0xffffffff, 0x00000100,
- 0x0409, 0xffffffff, 0x00000100,
- 0x040b, 0x00000101, 0x00000000,
- 0x082a, 0xffffffff, 0x00000104,
- 0x0993, 0x000c0000, 0x000c0000,
- 0x0992, 0x000c0000, 0x000c0000,
- 0x1579, 0xff000fff, 0x00000100,
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmMC_CITF_MISC_WR_CG, 0x000c0000, 0x000c0000,
+ mmMC_CITF_MISC_RD_CG, 0x000c0000, 0x000c0000,
+ mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
0x157a, 0x00000001, 0x00000001,
- 0x0bd4, 0x00000001, 0x00000001,
- 0x0c33, 0xc0000fff, 0x00000104,
- 0x3079, 0x00000001, 0x00000001,
+ mmHDP_MEM_POWER_LS, 0x00000001, 0x00000001,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
0x3430, 0xfffffff0, 0x00000100,
- 0x3630, 0xfffffff0, 0x00000100
+ 0x3630, 0xfffffff0, 0x00000100,
};
+
static const u32 hainan_mgcg_cgcg_init[] =
{
- 0x3100, 0xffffffff, 0xfffffffc,
- 0x200b, 0xffffffff, 0xe0000000,
- 0x2698, 0xffffffff, 0x00000100,
- 0x24a9, 0xffffffff, 0x00000100,
- 0x3059, 0xffffffff, 0x00000100,
- 0x25dd, 0xffffffff, 0x00000100,
- 0x2261, 0xffffffff, 0x06000100,
- 0x2286, 0xffffffff, 0x00000100,
- 0x24a8, 0xffffffff, 0x00000100,
- 0x30e0, 0xffffffff, 0x00000100,
- 0x22ca, 0xffffffff, 0x00000100,
- 0x2451, 0xffffffff, 0x00000100,
- 0x2362, 0xffffffff, 0x00000100,
- 0x2363, 0xffffffff, 0x00000100,
- 0x240c, 0xffffffff, 0x00000100,
- 0x240d, 0xffffffff, 0x00000100,
- 0x240e, 0xffffffff, 0x00000100,
- 0x240f, 0xffffffff, 0x00000100,
- 0x2b60, 0xffffffff, 0x00000100,
- 0x2b15, 0xffffffff, 0x00000100,
- 0x225f, 0xffffffff, 0x06000100,
- 0x261a, 0xffffffff, 0x00000100,
- 0x2544, 0xffffffff, 0x00000100,
- 0x2bc1, 0xffffffff, 0x00000100,
- 0x2b81, 0xffffffff, 0x00000100,
- 0x2527, 0xffffffff, 0x00000100,
- 0x200b, 0xffffffff, 0xe0000000,
+ mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xfffffffc,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
+ mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
+ mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
+ mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
+ mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
+ mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
+ mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
+ mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
+ mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
0x2458, 0xffffffff, 0x00010000,
0x2459, 0xffffffff, 0x00030002,
0x245a, 0xffffffff, 0x00040007,
@@ -870,22 +879,22 @@ static const u32 hainan_mgcg_cgcg_init[] =
0x2473, 0xffffffff, 0x0000000b,
0x2474, 0xffffffff, 0x000a0009,
0x2475, 0xffffffff, 0x000d000c,
- 0x2454, 0xffffffff, 0x96940200,
- 0x21c2, 0xffffffff, 0x00900100,
- 0x311e, 0xffffffff, 0x00000080,
- 0x3101, 0xffffffff, 0x0020003f,
+ mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
+ mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
+ mmRLC_GCPM_GENERAL_3, 0xffffffff, 0x00000080,
+ mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003f,
0x000c, 0xffffffff, 0x0000001c,
0x000d, 0x000f0000, 0x000f0000,
0x0583, 0xffffffff, 0x00000100,
0x0409, 0xffffffff, 0x00000100,
- 0x082a, 0xffffffff, 0x00000104,
- 0x0993, 0x000c0000, 0x000c0000,
- 0x0992, 0x000c0000, 0x000c0000,
- 0x0bd4, 0x00000001, 0x00000001,
- 0x0c33, 0xc0000fff, 0x00000104,
- 0x3079, 0x00000001, 0x00000001,
+ mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104,
+ mmMC_CITF_MISC_WR_CG, 0x000c0000, 0x000c0000,
+ mmMC_CITF_MISC_RD_CG, 0x000c0000, 0x000c0000,
+ mmHDP_MEM_POWER_LS, 0x00000001, 0x00000001,
+ mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
+ mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
0x3430, 0xfffffff0, 0x00000100,
- 0x3630, 0xfffffff0, 0x00000100
+ 0x3630, 0xfffffff0, 0x00000100,
};
static u32 si_pcie_rreg(struct amdgpu_device *adev, u32 reg)
@@ -1129,13 +1138,12 @@ static int si_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk)
static void si_detect_hw_virtualization(struct amdgpu_device *adev)
{
if (is_virtual_machine()) /* passthrough mode */
- adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
+ adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE;
}
static const struct amdgpu_asic_funcs si_asic_funcs =
{
.read_disabled_bios = &si_read_disabled_bios,
- .detect_hw_virtualization = si_detect_hw_virtualization,
.read_register = &si_read_register,
.reset = &si_asic_reset,
.set_vga_state = &si_vga_set_state,
@@ -1852,6 +1860,8 @@ static const struct amdgpu_ip_block_version si_common_ip_block =
int si_set_ip_blocks(struct amdgpu_device *adev)
{
+ si_detect_hw_virtualization(adev);
+
switch (adev->asic_type) {
case CHIP_VERDE:
case CHIP_TAHITI:
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index 3dd552ae0b59..3372a071bb85 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -24,7 +24,7 @@
#include <drm/drmP.h>
#include "amdgpu.h"
#include "amdgpu_trace.h"
-#include "si/sid.h"
+#include "sid.h"
const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
{
@@ -301,7 +301,7 @@ static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
ib.ptr[2] = upper_32_bits(gpu_addr) & 0xff;
ib.ptr[3] = 0xDEADBEEF;
ib.length_dw = 4;
- r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+ r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
goto err1;
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
index 6c65a1a2de79..f55e45b52fbc 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -26,7 +26,7 @@
#include "amdgpu_pm.h"
#include "amdgpu_dpm.h"
#include "amdgpu_atombios.h"
-#include "si/sid.h"
+#include "sid.h"
#include "r600_dpm.h"
#include "si_dpm.h"
#include "atom.h"
@@ -56,7 +56,6 @@
#define BIOS_SCRATCH_4 0x5cd
MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin");
MODULE_FIRMWARE("radeon/verde_smc.bin");
@@ -65,6 +64,7 @@ MODULE_FIRMWARE("radeon/oland_smc.bin");
MODULE_FIRMWARE("radeon/oland_k_smc.bin");
MODULE_FIRMWARE("radeon/hainan_smc.bin");
MODULE_FIRMWARE("radeon/hainan_k_smc.bin");
+MODULE_FIRMWARE("radeon/banks_k_2_smc.bin");
union power_info {
struct _ATOM_POWERPLAY_INFO info;
@@ -3009,29 +3009,6 @@ static int si_init_smc_spll_table(struct amdgpu_device *adev)
return ret;
}
-struct si_dpm_quirk {
- u32 chip_vendor;
- u32 chip_device;
- u32 subsys_vendor;
- u32 subsys_device;
- u32 max_sclk;
- u32 max_mclk;
-};
-
-/* cards with dpm stability problems */
-static struct si_dpm_quirk si_dpm_quirk_list[] = {
- /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
- { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 },
- { 0, 0, 0, 0 },
-};
-
static u16 si_get_lower_of_leakage_and_vce_voltage(struct amdgpu_device *adev,
u16 vce_voltage)
{
@@ -3477,42 +3454,8 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
u32 max_sclk = 0, max_mclk = 0;
int i;
- struct si_dpm_quirk *p = si_dpm_quirk_list;
- /* limit all SI kickers */
- if (adev->asic_type == CHIP_PITCAIRN) {
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->device == 0x6810) ||
- (adev->pdev->device == 0x6811) ||
- (adev->pdev->device == 0x6816) ||
- (adev->pdev->device == 0x6817) ||
- (adev->pdev->device == 0x6806))
- max_mclk = 120000;
- } else if (adev->asic_type == CHIP_VERDE) {
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6820) ||
- (adev->pdev->device == 0x6821) ||
- (adev->pdev->device == 0x6822) ||
- (adev->pdev->device == 0x6823) ||
- (adev->pdev->device == 0x682A) ||
- (adev->pdev->device == 0x682B)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (adev->asic_type == CHIP_OLAND) {
- if ((adev->pdev->revision == 0xC7) ||
- (adev->pdev->revision == 0x80) ||
- (adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6604) ||
- (adev->pdev->device == 0x6605)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (adev->asic_type == CHIP_HAINAN) {
+ if (adev->asic_type == CHIP_HAINAN) {
if ((adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0x83) ||
(adev->pdev->revision == 0xC3) ||
@@ -3520,20 +3463,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
(adev->pdev->device == 0x6665) ||
(adev->pdev->device == 0x6667)) {
max_sclk = 75000;
- max_mclk = 80000;
- }
- }
- /* Apply dpm quirks */
- while (p && p->chip_device != 0) {
- if (adev->pdev->vendor == p->chip_vendor &&
- adev->pdev->device == p->chip_device &&
- adev->pdev->subsystem_vendor == p->subsys_vendor &&
- adev->pdev->subsystem_device == p->subsys_device) {
- max_sclk = p->max_sclk;
- max_mclk = p->max_mclk;
- break;
}
- ++p;
}
if (rps->vce_active) {
@@ -3931,25 +3861,25 @@ static int si_restrict_performance_levels_before_switch(struct amdgpu_device *ad
}
static int si_dpm_force_performance_level(struct amdgpu_device *adev,
- enum amdgpu_dpm_forced_level level)
+ enum amd_dpm_forced_level level)
{
struct amdgpu_ps *rps = adev->pm.dpm.current_ps;
struct si_ps *ps = si_get_ps(rps);
u32 levels = ps->performance_level_count;
- if (level == AMDGPU_DPM_FORCED_LEVEL_HIGH) {
+ if (level == AMD_DPM_FORCED_LEVEL_HIGH) {
if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
return -EINVAL;
if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
return -EINVAL;
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_LOW) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_LOW) {
if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
return -EINVAL;
- } else if (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) {
+ } else if (level == AMD_DPM_FORCED_LEVEL_AUTO) {
if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
@@ -7687,50 +7617,51 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev)
chip_name = "tahiti";
break;
case CHIP_PITCAIRN:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->device == 0x6810) ||
- (adev->pdev->device == 0x6811) ||
- (adev->pdev->device == 0x6816) ||
- (adev->pdev->device == 0x6817) ||
- (adev->pdev->device == 0x6806))
+ if ((adev->pdev->revision == 0x81) &&
+ ((adev->pdev->device == 0x6810) ||
+ (adev->pdev->device == 0x6811)))
chip_name = "pitcairn_k";
else
chip_name = "pitcairn";
break;
case CHIP_VERDE:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6820) ||
- (adev->pdev->device == 0x6821) ||
- (adev->pdev->device == 0x6822) ||
- (adev->pdev->device == 0x6823) ||
- (adev->pdev->device == 0x682A) ||
- (adev->pdev->device == 0x682B))
+ if (((adev->pdev->device == 0x6820) &&
+ ((adev->pdev->revision == 0x81) ||
+ (adev->pdev->revision == 0x83))) ||
+ ((adev->pdev->device == 0x6821) &&
+ ((adev->pdev->revision == 0x83) ||
+ (adev->pdev->revision == 0x87))) ||
+ ((adev->pdev->revision == 0x87) &&
+ ((adev->pdev->device == 0x6823) ||
+ (adev->pdev->device == 0x682b))))
chip_name = "verde_k";
else
chip_name = "verde";
break;
case CHIP_OLAND:
- if ((adev->pdev->revision == 0xC7) ||
- (adev->pdev->revision == 0x80) ||
- (adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6604) ||
- (adev->pdev->device == 0x6605))
+ if (((adev->pdev->revision == 0x81) &&
+ ((adev->pdev->device == 0x6600) ||
+ (adev->pdev->device == 0x6604) ||
+ (adev->pdev->device == 0x6605) ||
+ (adev->pdev->device == 0x6610))) ||
+ ((adev->pdev->revision == 0x83) &&
+ (adev->pdev->device == 0x6610)))
chip_name = "oland_k";
else
chip_name = "oland";
break;
case CHIP_HAINAN:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0xC3) ||
- (adev->pdev->device == 0x6664) ||
- (adev->pdev->device == 0x6665) ||
- (adev->pdev->device == 0x6667))
+ if (((adev->pdev->revision == 0x81) &&
+ (adev->pdev->device == 0x6660)) ||
+ ((adev->pdev->revision == 0x83) &&
+ ((adev->pdev->device == 0x6660) ||
+ (adev->pdev->device == 0x6663) ||
+ (adev->pdev->device == 0x6665) ||
+ (adev->pdev->device == 0x6667))))
chip_name = "hainan_k";
+ else if ((adev->pdev->revision == 0xc3) &&
+ (adev->pdev->device == 0x6665))
+ chip_name = "banks_k_2";
else
chip_name = "hainan";
break;
@@ -7770,7 +7701,7 @@ static int si_dpm_sw_init(void *handle)
/* default to balanced state */
adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
- adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ adev->pm.dpm.forced_level = AMD_DPM_FORCED_LEVEL_AUTO;
adev->pm.default_sclk = adev->clock.default_sclk;
adev->pm.default_mclk = adev->clock.default_mclk;
adev->pm.current_sclk = adev->clock.default_sclk;
@@ -8096,11 +8027,3 @@ static void si_dpm_set_irq_funcs(struct amdgpu_device *adev)
adev->pm.dpm.thermal.irq.funcs = &si_dpm_irq_funcs;
}
-const struct amdgpu_ip_block_version si_dpm_ip_block =
-{
- .type = AMD_IP_BLOCK_TYPE_SMC,
- .major = 6,
- .minor = 0,
- .rev = 0,
- .funcs = &si_dpm_ip_funcs,
-};
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c
index db0f36846661..81f90800ba73 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c
@@ -23,7 +23,7 @@
#include "drmP.h"
#include "amdgpu.h"
#include "amdgpu_ih.h"
-#include "si/sid.h"
+#include "sid.h"
#include "si_ih.h"
static void si_ih_set_interrupt_funcs(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/si_smc.c b/drivers/gpu/drm/amd/amdgpu/si_smc.c
index 668ba99d6c05..0726bc3b6f90 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_smc.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_smc.c
@@ -25,7 +25,7 @@
#include <linux/firmware.h>
#include "drmP.h"
#include "amdgpu.h"
-#include "si/sid.h"
+#include "sid.h"
#include "ppsmc.h"
#include "amdgpu_ucode.h"
#include "sislands_smc.h"
diff --git a/drivers/gpu/drm/amd/include/asic_reg/si/sid.h b/drivers/gpu/drm/amd/amdgpu/sid.h
index c57eff159374..c57eff159374 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/si/sid.h
+++ b/drivers/gpu/drm/amd/amdgpu/sid.h
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_vi.h b/drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_vi.h
deleted file mode 100644
index 880152c0f775..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_vi.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef SMU_UCODE_XFER_VI_H
-#define SMU_UCODE_XFER_VI_H
-
-#define SMU_DRAMData_TOC_VERSION 1
-#define MAX_IH_REGISTER_COUNT 65535
-#define SMU_DIGEST_SIZE_BYTES 20
-#define SMU_FB_SIZE_BYTES 1048576
-#define SMU_MAX_ENTRIES 12
-
-#define UCODE_ID_SMU 0
-#define UCODE_ID_SDMA0 1
-#define UCODE_ID_SDMA1 2
-#define UCODE_ID_CP_CE 3
-#define UCODE_ID_CP_PFP 4
-#define UCODE_ID_CP_ME 5
-#define UCODE_ID_CP_MEC 6
-#define UCODE_ID_CP_MEC_JT1 7
-#define UCODE_ID_CP_MEC_JT2 8
-#define UCODE_ID_GMCON_RENG 9
-#define UCODE_ID_RLC_G 10
-#define UCODE_ID_IH_REG_RESTORE 11
-#define UCODE_ID_VBIOS 12
-#define UCODE_ID_MISC_METADATA 13
-#define UCODE_ID_SMU_SK 14
-#define UCODE_ID_RLC_SCRATCH 32
-#define UCODE_ID_RLC_SRM_ARAM 33
-#define UCODE_ID_RLC_SRM_DRAM 34
-#define UCODE_ID_MEC_STORAGE 35
-#define UCODE_ID_VBIOS_PARAMETERS 36
-#define UCODE_META_DATA 0xFF
-
-#define UCODE_ID_SMU_MASK 0x00000001
-#define UCODE_ID_SDMA0_MASK 0x00000002
-#define UCODE_ID_SDMA1_MASK 0x00000004
-#define UCODE_ID_CP_CE_MASK 0x00000008
-#define UCODE_ID_CP_PFP_MASK 0x00000010
-#define UCODE_ID_CP_ME_MASK 0x00000020
-#define UCODE_ID_CP_MEC_MASK 0x00000040
-#define UCODE_ID_CP_MEC_JT1_MASK 0x00000080
-#define UCODE_ID_CP_MEC_JT2_MASK 0x00000100
-#define UCODE_ID_GMCON_RENG_MASK 0x00000200
-#define UCODE_ID_RLC_G_MASK 0x00000400
-#define UCODE_ID_IH_REG_RESTORE_MASK 0x00000800
-#define UCODE_ID_VBIOS_MASK 0x00001000
-
-#define UCODE_FLAG_UNHALT_MASK 0x1
-
-struct SMU_Entry {
-#ifndef __BIG_ENDIAN
- uint16_t id;
- uint16_t version;
- uint32_t image_addr_high;
- uint32_t image_addr_low;
- uint32_t meta_data_addr_high;
- uint32_t meta_data_addr_low;
- uint32_t data_size_byte;
- uint16_t flags;
- uint16_t num_register_entries;
-#else
- uint16_t version;
- uint16_t id;
- uint32_t image_addr_high;
- uint32_t image_addr_low;
- uint32_t meta_data_addr_high;
- uint32_t meta_data_addr_low;
- uint32_t data_size_byte;
- uint16_t num_register_entries;
- uint16_t flags;
-#endif
-};
-
-struct SMU_DRAMData_TOC {
- uint32_t structure_version;
- uint32_t num_entries;
- struct SMU_Entry entry[SMU_MAX_ENTRIES];
-};
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
index 96444e4d862a..7fb9137dd89b 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -40,13 +40,14 @@
#include "smu/smu_7_0_1_sh_mask.h"
static void uvd_v4_2_mc_resume(struct amdgpu_device *adev);
-static void uvd_v4_2_init_cg(struct amdgpu_device *adev);
static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev);
static void uvd_v4_2_set_irq_funcs(struct amdgpu_device *adev);
static int uvd_v4_2_start(struct amdgpu_device *adev);
static void uvd_v4_2_stop(struct amdgpu_device *adev);
static int uvd_v4_2_set_clockgating_state(void *handle,
enum amd_clockgating_state state);
+static void uvd_v4_2_set_dcm(struct amdgpu_device *adev,
+ bool sw_mode);
/**
* uvd_v4_2_ring_get_rptr - get read pointer
*
@@ -140,7 +141,8 @@ static int uvd_v4_2_sw_fini(void *handle)
return r;
}
-
+static void uvd_v4_2_enable_mgcg(struct amdgpu_device *adev,
+ bool enable);
/**
* uvd_v4_2_hw_init - start and test UVD block
*
@@ -155,8 +157,7 @@ static int uvd_v4_2_hw_init(void *handle)
uint32_t tmp;
int r;
- uvd_v4_2_init_cg(adev);
- uvd_v4_2_set_clockgating_state(adev, AMD_CG_STATE_GATE);
+ uvd_v4_2_enable_mgcg(adev, true);
amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
r = uvd_v4_2_start(adev);
if (r)
@@ -266,11 +267,13 @@ static int uvd_v4_2_start(struct amdgpu_device *adev)
struct amdgpu_ring *ring = &adev->uvd.ring;
uint32_t rb_bufsz;
int i, j, r;
-
/* disable byte swapping */
u32 lmi_swap_cntl = 0;
u32 mp_swap_cntl = 0;
+ WREG32(mmUVD_CGC_GATE, 0);
+ uvd_v4_2_set_dcm(adev, true);
+
uvd_v4_2_mc_resume(adev);
/* disable interupt */
@@ -406,6 +409,8 @@ static void uvd_v4_2_stop(struct amdgpu_device *adev)
/* Unstall UMC and register bus */
WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8));
+
+ uvd_v4_2_set_dcm(adev, false);
}
/**
@@ -619,19 +624,6 @@ static void uvd_v4_2_set_dcm(struct amdgpu_device *adev,
WREG32_UVD_CTX(ixUVD_CGC_CTRL2, tmp2);
}
-static void uvd_v4_2_init_cg(struct amdgpu_device *adev)
-{
- bool hw_mode = true;
-
- if (hw_mode) {
- uvd_v4_2_set_dcm(adev, false);
- } else {
- u32 tmp = RREG32(mmUVD_CGC_CTRL);
- tmp &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
- WREG32(mmUVD_CGC_CTRL, tmp);
- }
-}
-
static bool uvd_v4_2_is_idle(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -685,17 +677,6 @@ static int uvd_v4_2_process_interrupt(struct amdgpu_device *adev,
static int uvd_v4_2_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
- bool gate = false;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
- return 0;
-
- if (state == AMD_CG_STATE_GATE)
- gate = true;
-
- uvd_v4_2_enable_mgcg(adev, gate);
-
return 0;
}
@@ -711,9 +692,6 @@ static int uvd_v4_2_set_powergating_state(void *handle,
*/
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
- return 0;
-
if (state == AMD_PG_STATE_GATE) {
uvd_v4_2_stop(adev);
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
index a79e283590fb..9b49824233ae 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
@@ -791,15 +791,10 @@ static int uvd_v5_0_set_clockgating_state(void *handle,
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
- static int curstate = -1;
if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
return 0;
- if (curstate == state)
- return 0;
-
- curstate = state;
if (enable) {
/* wait for STATUS to clear */
if (uvd_v5_0_wait_for_idle(handle))
@@ -827,16 +822,44 @@ static int uvd_v5_0_set_powergating_state(void *handle,
* the smc and the hw blocks
*/
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
return 0;
if (state == AMD_PG_STATE_GATE) {
uvd_v5_0_stop(adev);
- return 0;
+ adev->uvd.is_powergated = true;
} else {
- return uvd_v5_0_start(adev);
+ ret = uvd_v5_0_start(adev);
+ if (ret)
+ goto out;
+ adev->uvd.is_powergated = false;
+ }
+
+out:
+ return ret;
+}
+
+static void uvd_v5_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ mutex_lock(&adev->pm.mutex);
+
+ if (adev->uvd.is_powergated) {
+ DRM_INFO("Cannot get clockgating state when UVD is powergated.\n");
+ goto out;
}
+
+ /* AMD_CG_SUPPORT_UVD_MGCG */
+ data = RREG32(mmUVD_CGC_CTRL);
+ if (data & UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK)
+ *flags |= AMD_CG_SUPPORT_UVD_MGCG;
+
+out:
+ mutex_unlock(&adev->pm.mutex);
}
static const struct amd_ip_funcs uvd_v5_0_ip_funcs = {
@@ -854,6 +877,7 @@ static const struct amd_ip_funcs uvd_v5_0_ip_funcs = {
.soft_reset = uvd_v5_0_soft_reset,
.set_clockgating_state = uvd_v5_0_set_clockgating_state,
.set_powergating_state = uvd_v5_0_set_powergating_state,
+ .get_clockgating_state = uvd_v5_0_get_clockgating_state,
};
static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index ba0bbf7138dc..de7e03544d00 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -1047,6 +1047,7 @@ static int uvd_v6_0_set_powergating_state(void *handle,
* the smc and the hw blocks
*/
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
return 0;
@@ -1055,10 +1056,37 @@ static int uvd_v6_0_set_powergating_state(void *handle,
if (state == AMD_PG_STATE_GATE) {
uvd_v6_0_stop(adev);
- return 0;
+ adev->uvd.is_powergated = true;
} else {
- return uvd_v6_0_start(adev);
+ ret = uvd_v6_0_start(adev);
+ if (ret)
+ goto out;
+ adev->uvd.is_powergated = false;
+ }
+
+out:
+ return ret;
+}
+
+static void uvd_v6_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ mutex_lock(&adev->pm.mutex);
+
+ if (adev->uvd.is_powergated) {
+ DRM_INFO("Cannot get clockgating state when UVD is powergated.\n");
+ goto out;
}
+
+ /* AMD_CG_SUPPORT_UVD_MGCG */
+ data = RREG32(mmUVD_CGC_CTRL);
+ if (data & UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK)
+ *flags |= AMD_CG_SUPPORT_UVD_MGCG;
+
+out:
+ mutex_unlock(&adev->pm.mutex);
}
static const struct amd_ip_funcs uvd_v6_0_ip_funcs = {
@@ -1079,6 +1107,7 @@ static const struct amd_ip_funcs uvd_v6_0_ip_funcs = {
.post_soft_reset = uvd_v6_0_post_soft_reset,
.set_clockgating_state = uvd_v6_0_set_clockgating_state,
.set_powergating_state = uvd_v6_0_set_powergating_state,
+ .get_clockgating_state = uvd_v6_0_get_clockgating_state,
};
static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 6b3293a1c7b8..8db26559fd1b 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -43,9 +43,13 @@
#define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04
#define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10
+#define GRBM_GFX_INDEX__VCE_ALL_PIPE 0x07
+
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618
+#define mmGRBM_GFX_INDEX_DEFAULT 0xE0000000
+
#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02
#define VCE_V3_0_FW_SIZE (384 * 1024)
@@ -54,6 +58,9 @@
#define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8))
+#define GET_VCE_INSTANCE(i) ((i) << GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT \
+ | GRBM_GFX_INDEX__VCE_ALL_PIPE)
+
static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
@@ -175,7 +182,7 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
- data &= ~0xffc00000;
+ data &= ~0x3ff;
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
@@ -223,6 +230,10 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
struct amdgpu_ring *ring;
int idx, r;
+ vce_v3_0_override_vce_clock_gating(adev, true);
+ if (!(adev->flags & AMD_IS_APU))
+ amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
+
ring = &adev->vce.ring[0];
WREG32(mmVCE_RB_RPTR, ring->wptr);
WREG32(mmVCE_RB_WPTR, ring->wptr);
@@ -249,7 +260,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
if (adev->vce.harvest_config & (1 << idx))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
vce_v3_0_mc_resume(adev, idx);
WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
@@ -273,7 +284,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
}
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
@@ -288,7 +299,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev)
if (adev->vce.harvest_config & (1 << idx))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
if (adev->asic_type >= CHIP_STONEY)
WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
@@ -306,7 +317,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev)
vce_v3_0_set_vce_sw_clock_gating(adev, false);
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
@@ -320,11 +331,12 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
{
u32 tmp;
- /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
+ /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */
if ((adev->asic_type == CHIP_FIJI) ||
(adev->asic_type == CHIP_STONEY) ||
(adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11))
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12))
return AMDGPU_VCE_HARVEST_VCE1;
/* Tonga and CZ are dual or single pipe */
@@ -585,17 +597,17 @@ static bool vce_v3_0_check_soft_reset(void *handle)
* VCE team suggest use bit 3--bit 6 for busy status check
*/
mutex_lock(&adev->grbm_idx_mutex);
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1));
if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
mutex_unlock(&adev->grbm_idx_mutex);
if (srbm_soft_reset) {
@@ -700,18 +712,6 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
return 0;
}
-static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable)
-{
- u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
-
- if (enable)
- tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
- else
- tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
-
- WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
-}
-
static int vce_v3_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
@@ -719,11 +719,6 @@ static int vce_v3_0_set_clockgating_state(void *handle,
bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
int i;
- if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_TONGA) ||
- (adev->asic_type == CHIP_FIJI))
- vce_v3_0_set_bypass_mode(adev, enable);
-
if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
return 0;
@@ -733,7 +728,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
if (adev->vce.harvest_config & (1 << i))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i));
if (enable) {
/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
@@ -752,7 +747,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
vce_v3_0_set_vce_sw_clock_gating(adev, enable);
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
@@ -769,15 +764,46 @@ static int vce_v3_0_set_powergating_state(void *handle,
* the smc and the hw blocks
*/
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
return 0;
- if (state == AMD_PG_STATE_GATE)
+ if (state == AMD_PG_STATE_GATE) {
+ adev->vce.is_powergated = true;
/* XXX do we need a vce_v3_0_stop()? */
- return 0;
- else
- return vce_v3_0_start(adev);
+ } else {
+ ret = vce_v3_0_start(adev);
+ if (ret)
+ goto out;
+ adev->vce.is_powergated = false;
+ }
+
+out:
+ return ret;
+}
+
+static void vce_v3_0_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ mutex_lock(&adev->pm.mutex);
+
+ if (adev->vce.is_powergated) {
+ DRM_INFO("Cannot get clockgating state when VCE is powergated.\n");
+ goto out;
+ }
+
+ WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+
+ /* AMD_CG_SUPPORT_VCE_MGCG */
+ data = RREG32(mmVCE_CLOCK_GATING_A);
+ if (data & (0x04 << 4))
+ *flags |= AMD_CG_SUPPORT_VCE_MGCG;
+
+out:
+ mutex_unlock(&adev->pm.mutex);
}
static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
@@ -831,6 +857,7 @@ static const struct amd_ip_funcs vce_v3_0_ip_funcs = {
.post_soft_reset = vce_v3_0_post_soft_reset,
.set_clockgating_state = vce_v3_0_set_clockgating_state,
.set_powergating_state = vce_v3_0_set_powergating_state,
+ .get_clockgating_state = vce_v3_0_get_clockgating_state,
};
static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index bf088d6d9bf1..4922fff08c3c 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -20,9 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
-#include <linux/firmware.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include "drmP.h"
#include "amdgpu.h"
#include "amdgpu_atombios.h"
@@ -78,16 +76,7 @@
#include "amdgpu_acp.h"
#endif
#include "dce_virtual.h"
-
-MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
-MODULE_FIRMWARE("amdgpu/topaz_k_smc.bin");
-MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
-MODULE_FIRMWARE("amdgpu/tonga_k_smc.bin");
-MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
-MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
-MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
-MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
-MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin");
+#include "mxgpu_vi.h"
/*
* Indirect registers accessor
@@ -284,6 +273,12 @@ static void vi_init_golden_registers(struct amdgpu_device *adev)
/* Some of the registers might be dependent on GRBM_GFX_INDEX */
mutex_lock(&adev->grbm_idx_mutex);
+ if (amdgpu_sriov_vf(adev)) {
+ xgpu_vi_init_golden_registers(adev);
+ mutex_unlock(&adev->grbm_idx_mutex);
+ return;
+ }
+
switch (adev->asic_type) {
case CHIP_TOPAZ:
amdgpu_program_register_sequence(adev,
@@ -312,6 +307,7 @@ static void vi_init_golden_registers(struct amdgpu_device *adev)
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
default:
break;
}
@@ -456,14 +452,14 @@ static void vi_detect_hw_virtualization(struct amdgpu_device *adev)
/* bit0: 0 means pf and 1 means vf */
/* bit31: 0 means disable IOV and 1 means enable */
if (reg & 1)
- adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_IS_VF;
+ adev->virt.caps |= AMDGPU_SRIOV_CAPS_IS_VF;
if (reg & 0x80000000)
- adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_ENABLE_IOV;
+ adev->virt.caps |= AMDGPU_SRIOV_CAPS_ENABLE_IOV;
if (reg == 0) {
if (is_virtual_machine()) /* passthrough mode exclus sr-iov mode */
- adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
+ adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE;
}
}
@@ -671,6 +667,7 @@ static int vi_read_register(struct amdgpu_device *adev, u32 se_num,
case CHIP_TONGA:
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_CARRIZO:
case CHIP_STONEY:
asic_register_table = cz_allowed_read_registers;
@@ -798,7 +795,37 @@ static int vi_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk)
static int vi_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk)
{
- /* todo */
+ int r, i;
+ struct atom_clock_dividers dividers;
+ u32 tmp;
+
+ r = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ ecclk, false, &dividers);
+ if (r)
+ return r;
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(ixCG_ECLK_STATUS) & CG_ECLK_STATUS__ECLK_STATUS_MASK)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+
+ tmp = RREG32_SMC(ixCG_ECLK_CNTL);
+ tmp &= ~(CG_ECLK_CNTL__ECLK_DIR_CNTL_EN_MASK |
+ CG_ECLK_CNTL__ECLK_DIVIDER_MASK);
+ tmp |= dividers.post_divider;
+ WREG32_SMC(ixCG_ECLK_CNTL, tmp);
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(ixCG_ECLK_STATUS) & CG_ECLK_STATUS__ECLK_STATUS_MASK)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
return 0;
}
@@ -866,7 +893,6 @@ static const struct amdgpu_asic_funcs vi_asic_funcs =
{
.read_disabled_bios = &vi_read_disabled_bios,
.read_bios_from_rom = &vi_read_bios_from_rom,
- .detect_hw_virtualization = vi_detect_hw_virtualization,
.read_register = &vi_read_register,
.reset = &vi_asic_reset,
.set_vga_state = &vi_vga_set_state,
@@ -902,6 +928,11 @@ static int vi_common_early_init(void *handle)
(amdgpu_ip_block_mask & (1 << AMD_IP_BLOCK_TYPE_SMC)))
smc_enabled = true;
+ if (amdgpu_sriov_vf(adev)) {
+ amdgpu_virt_init_setting(adev);
+ xgpu_vi_mailbox_set_irq_funcs(adev);
+ }
+
adev->rev_id = vi_get_rev_id(adev);
adev->external_rev_id = 0xFF;
switch (adev->asic_type) {
@@ -994,6 +1025,11 @@ static int vi_common_early_init(void *handle)
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x50;
break;
+ case CHIP_POLARIS12:
+ adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
+ adev->pg_flags = 0;
+ adev->external_rev_id = adev->rev_id + 0x64;
+ break;
case CHIP_CARRIZO:
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
AMD_CG_SUPPORT_GFX_MGCG |
@@ -1053,10 +1089,6 @@ static int vi_common_early_init(void *handle)
return -EINVAL;
}
- /* in early init stage, vbios code won't work */
- if (adev->asic_funcs->detect_hw_virtualization)
- amdgpu_asic_detect_hw_virtualization(adev);
-
if (amdgpu_smc_load_fw && smc_enabled)
adev->firmware.smu_load = true;
@@ -1065,8 +1097,23 @@ static int vi_common_early_init(void *handle)
return 0;
}
+static int vi_common_late_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (amdgpu_sriov_vf(adev))
+ xgpu_vi_mailbox_get_irq(adev);
+
+ return 0;
+}
+
static int vi_common_sw_init(void *handle)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (amdgpu_sriov_vf(adev))
+ xgpu_vi_mailbox_add_irq_id(adev);
+
return 0;
}
@@ -1098,6 +1145,9 @@ static int vi_common_hw_fini(void *handle)
/* enable the doorbell aperture */
vi_enable_doorbell_aperture(adev, false);
+ if (amdgpu_sriov_vf(adev))
+ xgpu_vi_mailbox_put_irq(adev);
+
return 0;
}
@@ -1182,6 +1232,23 @@ static void vi_update_hdp_light_sleep(struct amdgpu_device *adev,
WREG32(mmHDP_MEM_POWER_LS, data);
}
+static void vi_update_drm_light_sleep(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ temp = data = RREG32(0x157a);
+
+ if (enable && (adev->cg_flags & AMD_CG_SUPPORT_DRM_LS))
+ data |= 1;
+ else
+ data &= ~1;
+
+ if (temp != data)
+ WREG32(0x157a, data);
+}
+
+
static void vi_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
bool enable)
{
@@ -1342,10 +1409,13 @@ static int vi_common_set_clockgating_state(void *handle,
state == AMD_CG_STATE_GATE ? true : false);
vi_update_hdp_light_sleep(adev,
state == AMD_CG_STATE_GATE ? true : false);
+ vi_update_drm_light_sleep(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
break;
case CHIP_TONGA:
case CHIP_POLARIS10:
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
vi_common_set_clockgating_state_by_smu(adev, state);
default:
break;
@@ -1359,10 +1429,36 @@ static int vi_common_set_powergating_state(void *handle,
return 0;
}
+static void vi_common_get_clockgating_state(void *handle, u32 *flags)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int data;
+
+ /* AMD_CG_SUPPORT_BIF_LS */
+ data = RREG32_PCIE(ixPCIE_CNTL2);
+ if (data & PCIE_CNTL2__SLV_MEM_LS_EN_MASK)
+ *flags |= AMD_CG_SUPPORT_BIF_LS;
+
+ /* AMD_CG_SUPPORT_HDP_LS */
+ data = RREG32(mmHDP_MEM_POWER_LS);
+ if (data & HDP_MEM_POWER_LS__LS_ENABLE_MASK)
+ *flags |= AMD_CG_SUPPORT_HDP_LS;
+
+ /* AMD_CG_SUPPORT_HDP_MGCG */
+ data = RREG32(mmHDP_HOST_PATH_CNTL);
+ if (!(data & HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK))
+ *flags |= AMD_CG_SUPPORT_HDP_MGCG;
+
+ /* AMD_CG_SUPPORT_ROM_MGCG */
+ data = RREG32_SMC(ixCGTT_ROM_CLK_CTRL0);
+ if (!(data & CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK))
+ *flags |= AMD_CG_SUPPORT_ROM_MGCG;
+}
+
static const struct amd_ip_funcs vi_common_ip_funcs = {
.name = "vi_common",
.early_init = vi_common_early_init,
- .late_init = NULL,
+ .late_init = vi_common_late_init,
.sw_init = vi_common_sw_init,
.sw_fini = vi_common_sw_fini,
.hw_init = vi_common_hw_init,
@@ -1374,6 +1470,7 @@ static const struct amd_ip_funcs vi_common_ip_funcs = {
.soft_reset = vi_common_soft_reset,
.set_clockgating_state = vi_common_set_clockgating_state,
.set_powergating_state = vi_common_set_powergating_state,
+ .get_clockgating_state = vi_common_get_clockgating_state,
};
static const struct amdgpu_ip_block_version vi_common_ip_block =
@@ -1387,6 +1484,12 @@ static const struct amdgpu_ip_block_version vi_common_ip_block =
int vi_set_ip_blocks(struct amdgpu_device *adev)
{
+ /* in early init stage, vbios code won't work */
+ vi_detect_hw_virtualization(adev);
+
+ if (amdgpu_sriov_vf(adev))
+ adev->virt.ops = &xgpu_vi_virt_ops;
+
switch (adev->asic_type) {
case CHIP_TOPAZ:
/* topaz has no DCE, UVD, VCE */
@@ -1404,31 +1507,36 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_ip_block_add(adev, &gmc_v8_5_ip_block);
amdgpu_ip_block_add(adev, &tonga_ih_ip_block);
amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
- if (adev->enable_virtual_display)
+ if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
else
amdgpu_ip_block_add(adev, &dce_v10_1_ip_block);
amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
amdgpu_ip_block_add(adev, &sdma_v3_0_ip_block);
- amdgpu_ip_block_add(adev, &uvd_v6_0_ip_block);
- amdgpu_ip_block_add(adev, &vce_v3_0_ip_block);
+ if (!amdgpu_sriov_vf(adev)) {
+ amdgpu_ip_block_add(adev, &uvd_v6_0_ip_block);
+ amdgpu_ip_block_add(adev, &vce_v3_0_ip_block);
+ }
break;
case CHIP_TONGA:
amdgpu_ip_block_add(adev, &vi_common_ip_block);
amdgpu_ip_block_add(adev, &gmc_v8_0_ip_block);
amdgpu_ip_block_add(adev, &tonga_ih_ip_block);
amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
- if (adev->enable_virtual_display)
+ if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
else
amdgpu_ip_block_add(adev, &dce_v10_0_ip_block);
amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
amdgpu_ip_block_add(adev, &sdma_v3_0_ip_block);
- amdgpu_ip_block_add(adev, &uvd_v5_0_ip_block);
- amdgpu_ip_block_add(adev, &vce_v3_0_ip_block);
+ if (!amdgpu_sriov_vf(adev)) {
+ amdgpu_ip_block_add(adev, &uvd_v5_0_ip_block);
+ amdgpu_ip_block_add(adev, &vce_v3_0_ip_block);
+ }
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
amdgpu_ip_block_add(adev, &vi_common_ip_block);
amdgpu_ip_block_add(adev, &gmc_v8_1_ip_block);
amdgpu_ip_block_add(adev, &tonga_ih_ip_block);
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.h b/drivers/gpu/drm/amd/amdgpu/vi.h
index 575d7aed5d32..719587b8b0cb 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.h
+++ b/drivers/gpu/drm/amd/amdgpu/vi.h
@@ -28,4 +28,116 @@ void vi_srbm_select(struct amdgpu_device *adev,
u32 me, u32 pipe, u32 queue, u32 vmid);
int vi_set_ip_blocks(struct amdgpu_device *adev);
+struct amdgpu_ce_ib_state
+{
+ uint32_t ce_ib_completion_status;
+ uint32_t ce_constegnine_count;
+ uint32_t ce_ibOffset_ib1;
+ uint32_t ce_ibOffset_ib2;
+}; /* Total of 4 DWORD */
+
+struct amdgpu_de_ib_state
+{
+ uint32_t ib_completion_status;
+ uint32_t de_constEngine_count;
+ uint32_t ib_offset_ib1;
+ uint32_t ib_offset_ib2;
+ uint32_t preamble_begin_ib1;
+ uint32_t preamble_begin_ib2;
+ uint32_t preamble_end_ib1;
+ uint32_t preamble_end_ib2;
+ uint32_t draw_indirect_baseLo;
+ uint32_t draw_indirect_baseHi;
+ uint32_t disp_indirect_baseLo;
+ uint32_t disp_indirect_baseHi;
+ uint32_t gds_backup_addrlo;
+ uint32_t gds_backup_addrhi;
+ uint32_t index_base_addrlo;
+ uint32_t index_base_addrhi;
+ uint32_t sample_cntl;
+}; /* Total of 17 DWORD */
+
+struct amdgpu_ce_ib_state_chained_ib
+{
+ /* section of non chained ib part */
+ uint32_t ce_ib_completion_status;
+ uint32_t ce_constegnine_count;
+ uint32_t ce_ibOffset_ib1;
+ uint32_t ce_ibOffset_ib2;
+
+ /* section of chained ib */
+ uint32_t ce_chainib_addrlo_ib1;
+ uint32_t ce_chainib_addrlo_ib2;
+ uint32_t ce_chainib_addrhi_ib1;
+ uint32_t ce_chainib_addrhi_ib2;
+ uint32_t ce_chainib_size_ib1;
+ uint32_t ce_chainib_size_ib2;
+}; /* total 10 DWORD */
+
+struct amdgpu_de_ib_state_chained_ib
+{
+ /* section of non chained ib part */
+ uint32_t ib_completion_status;
+ uint32_t de_constEngine_count;
+ uint32_t ib_offset_ib1;
+ uint32_t ib_offset_ib2;
+
+ /* section of chained ib */
+ uint32_t chain_ib_addrlo_ib1;
+ uint32_t chain_ib_addrlo_ib2;
+ uint32_t chain_ib_addrhi_ib1;
+ uint32_t chain_ib_addrhi_ib2;
+ uint32_t chain_ib_size_ib1;
+ uint32_t chain_ib_size_ib2;
+
+ /* section of non chained ib part */
+ uint32_t preamble_begin_ib1;
+ uint32_t preamble_begin_ib2;
+ uint32_t preamble_end_ib1;
+ uint32_t preamble_end_ib2;
+
+ /* section of chained ib */
+ uint32_t chain_ib_pream_addrlo_ib1;
+ uint32_t chain_ib_pream_addrlo_ib2;
+ uint32_t chain_ib_pream_addrhi_ib1;
+ uint32_t chain_ib_pream_addrhi_ib2;
+
+ /* section of non chained ib part */
+ uint32_t draw_indirect_baseLo;
+ uint32_t draw_indirect_baseHi;
+ uint32_t disp_indirect_baseLo;
+ uint32_t disp_indirect_baseHi;
+ uint32_t gds_backup_addrlo;
+ uint32_t gds_backup_addrhi;
+ uint32_t index_base_addrlo;
+ uint32_t index_base_addrhi;
+ uint32_t sample_cntl;
+}; /* Total of 27 DWORD */
+
+struct amdgpu_gfx_meta_data
+{
+ /* 4 DWORD, address must be 4KB aligned */
+ struct amdgpu_ce_ib_state ce_payload;
+ uint32_t reserved1[60];
+ /* 17 DWORD, address must be 64B aligned */
+ struct amdgpu_de_ib_state de_payload;
+ /* PFP IB base address which get pre-empted */
+ uint32_t DeIbBaseAddrLo;
+ uint32_t DeIbBaseAddrHi;
+ uint32_t reserved2[941];
+}; /* Total of 4K Bytes */
+
+struct amdgpu_gfx_meta_data_chained_ib
+{
+ /* 10 DWORD, address must be 4KB aligned */
+ struct amdgpu_ce_ib_state_chained_ib ce_payload;
+ uint32_t reserved1[54];
+ /* 27 DWORD, address must be 64B aligned */
+ struct amdgpu_de_ib_state_chained_ib de_payload;
+ /* PFP IB base address which get pre-empted */
+ uint32_t DeIbBaseAddrLo;
+ uint32_t DeIbBaseAddrHi;
+ uint32_t reserved2[931];
+}; /* Total of 4K Bytes */
+
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/vi_dpm.h b/drivers/gpu/drm/amd/amdgpu/vi_dpm.h
index fc120ba18aad..c43e03fddfba 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/vi_dpm.h
@@ -29,8 +29,4 @@ int cz_smu_init(struct amdgpu_device *adev);
int cz_smu_start(struct amdgpu_device *adev);
int cz_smu_fini(struct amdgpu_device *adev);
-extern const struct amd_ip_funcs tonga_dpm_ip_funcs;
-extern const struct amd_ip_funcs fiji_dpm_ip_funcs;
-extern const struct amd_ip_funcs iceland_dpm_ip_funcs;
-
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/vid.h b/drivers/gpu/drm/amd/amdgpu/vid.h
index 11746f22d0c5..7a3863a45f0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vid.h
+++ b/drivers/gpu/drm/amd/amdgpu/vid.h
@@ -360,6 +360,8 @@
#define PACKET3_WAIT_ON_CE_COUNTER 0x86
#define PACKET3_WAIT_ON_DE_COUNTER_DIFF 0x88
#define PACKET3_SWITCH_BUFFER 0x8B
+#define PACKET3_SET_RESOURCES 0xA0
+#define PACKET3_MAP_QUEUES 0xA2
#define VCE_CMD_NO_OP 0x00000000
#define VCE_CMD_END 0x00000001
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index c02469ada9f1..43f45adeccd1 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -23,7 +23,7 @@
#ifndef __AMD_SHARED_H__
#define __AMD_SHARED_H__
-#define AMD_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+#define AMD_MAX_USEC_TIMEOUT 200000 /* 200 ms */
/*
* Supported ASIC types
@@ -46,6 +46,7 @@ enum amd_asic_type {
CHIP_STONEY,
CHIP_POLARIS10,
CHIP_POLARIS11,
+ CHIP_POLARIS12,
CHIP_LAST,
};
@@ -79,6 +80,18 @@ enum amd_clockgating_state {
AMD_CG_STATE_UNGATE,
};
+enum amd_dpm_forced_level {
+ AMD_DPM_FORCED_LEVEL_AUTO = 0x1,
+ AMD_DPM_FORCED_LEVEL_MANUAL = 0x2,
+ AMD_DPM_FORCED_LEVEL_LOW = 0x4,
+ AMD_DPM_FORCED_LEVEL_HIGH = 0x8,
+ AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD = 0x10,
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK = 0x20,
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK = 0x40,
+ AMD_DPM_FORCED_LEVEL_PROFILE_PEAK = 0x80,
+ AMD_DPM_FORCED_LEVEL_PROFILE_EXIT = 0x100,
+};
+
enum amd_powergating_state {
AMD_PG_STATE_GATE = 0,
AMD_PG_STATE_UNGATE,
@@ -205,6 +218,8 @@ struct amd_ip_funcs {
/* enable/disable pg for the IP block */
int (*set_powergating_state)(void *handle,
enum amd_powergating_state state);
+ /* get current clockgating status */
+ void (*get_clockgating_state)(void *handle, u32 *flags);
};
#endif /* __AMD_SHARED_H__ */
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h
index 95570dbd18bb..813957a17a2d 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h
@@ -4552,6 +4552,14 @@
#define mmDP4_DP_DPHY_PRBS_CNTL 0x4eb5
#define mmDP5_DP_DPHY_PRBS_CNTL 0x4fb5
#define mmDP6_DP_DPHY_PRBS_CNTL 0x54b5
+#define mmDP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP0_DP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP1_DP_DPHY_SCRAM_CNTL 0x4bb6
+#define mmDP2_DP_DPHY_SCRAM_CNTL 0x4cb6
+#define mmDP3_DP_DPHY_SCRAM_CNTL 0x4db6
+#define mmDP4_DP_DPHY_SCRAM_CNTL 0x4eb6
+#define mmDP5_DP_DPHY_SCRAM_CNTL 0x4fb6
+#define mmDP6_DP_DPHY_SCRAM_CNTL 0x54b6
#define mmDP_DPHY_CRC_EN 0x4ab7
#define mmDP0_DP_DPHY_CRC_EN 0x4ab7
#define mmDP1_DP_DPHY_CRC_EN 0x4bb7
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h
index 8a75eb9d732b..c755f43aaaf8 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h
@@ -8690,6 +8690,10 @@
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEL__SHIFT 0x4
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED_MASK 0x7fffff00
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED__SHIFT 0x8
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE_MASK 0x10
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE__SHIFT 0x4
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT_MASK 0x3ff00
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT__SHIFT 0x8
#define DP_DPHY_CRC_EN__DPHY_CRC_EN_MASK 0x1
#define DP_DPHY_CRC_EN__DPHY_CRC_EN__SHIFT 0x0
#define DP_DPHY_CRC_EN__DPHY_CRC_CONT_EN_MASK 0x10
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h
index c39234ecedd0..6df651a94b0a 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h
@@ -4544,6 +4544,15 @@
#define mmDP6_DP_DPHY_PRBS_CNTL 0x54b5
#define mmDP7_DP_DPHY_PRBS_CNTL 0x56b5
#define mmDP8_DP_DPHY_PRBS_CNTL 0x57b5
+#define mmDP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP0_DP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP1_DP_DPHY_SCRAM_CNTL 0x4bb6
+#define mmDP2_DP_DPHY_SCRAM_CNTL 0x4cb6
+#define mmDP3_DP_DPHY_SCRAM_CNTL 0x4db6
+#define mmDP4_DP_DPHY_SCRAM_CNTL 0x4eb6
+#define mmDP5_DP_DPHY_SCRAM_CNTL 0x4fb6
+#define mmDP6_DP_DPHY_SCRAM_CNTL 0x54b6
+#define mmDP8_DP_DPHY_SCRAM_CNTL 0x56b6
#define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4adc
#define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4adc
#define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4bdc
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h
index a438c2b6e280..14a3bacfcfd1 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h
@@ -6004,6 +6004,8 @@
#define DIG_DISPCLK_SWITCH_STATUS__DIG_DISPCLK_SWITCH_ALLOWED_INT_MASK__SHIFT 0xc
#define HDMI_CONTROL__HDMI_KEEPOUT_MODE_MASK 0x1
#define HDMI_CONTROL__HDMI_KEEPOUT_MODE__SHIFT 0x0
+#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK 0x2
+#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN__SHIFT 0x1
#define HDMI_CONTROL__HDMI_CLOCK_CHANNEL_RATE_MASK 0x4
#define HDMI_CONTROL__HDMI_CLOCK_CHANNEL_RATE__SHIFT 0x2
#define HDMI_CONTROL__HDMI_NO_EXTRA_NULL_PACKET_FILLED_MASK 0x8
@@ -8364,6 +8366,10 @@
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEL__SHIFT 0x4
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED_MASK 0x7fffff00
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED__SHIFT 0x8
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE_MASK 0x10
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE__SHIFT 0x4
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT_MASK 0x3ff00
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT__SHIFT 0x8
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_LOAD_BS_COUNT_MASK 0x3ff
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_LOAD_BS_COUNT__SHIFT 0x0
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_BS_SR_SWAP_DONE_MASK 0x8000
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_d.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_d.h
index 09a7df17570d..367b191d49fb 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_d.h
@@ -5776,6 +5776,15 @@
#define mmDP6_DP_DPHY_PRBS_CNTL 0x54b5
#define mmDP7_DP_DPHY_PRBS_CNTL 0x56b5
#define mmDP8_DP_DPHY_PRBS_CNTL 0x57b5
+#define mmDP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP0_DP_DPHY_SCRAM_CNTL 0x4ab6
+#define mmDP1_DP_DPHY_SCRAM_CNTL 0x4bb6
+#define mmDP2_DP_DPHY_SCRAM_CNTL 0x4cb6
+#define mmDP3_DP_DPHY_SCRAM_CNTL 0x4db6
+#define mmDP4_DP_DPHY_SCRAM_CNTL 0x4eb6
+#define mmDP5_DP_DPHY_SCRAM_CNTL 0x4fb6
+#define mmDP6_DP_DPHY_SCRAM_CNTL 0x54b6
+#define mmDP8_DP_DPHY_SCRAM_CNTL 0x56b6
#define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4adc
#define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4adc
#define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4bdc
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_sh_mask.h
index 1ddc4183a1c9..106094ed0661 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_2_sh_mask.h
@@ -7088,6 +7088,8 @@
#define DIG_DISPCLK_SWITCH_STATUS__DIG_DISPCLK_SWITCH_ALLOWED_INT_MASK__SHIFT 0xc
#define HDMI_CONTROL__HDMI_KEEPOUT_MODE_MASK 0x1
#define HDMI_CONTROL__HDMI_KEEPOUT_MODE__SHIFT 0x0
+#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK 0x2
+#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN__SHIFT 0x1
#define HDMI_CONTROL__HDMI_CLOCK_CHANNEL_RATE_MASK 0x4
#define HDMI_CONTROL__HDMI_CLOCK_CHANNEL_RATE__SHIFT 0x2
#define HDMI_CONTROL__HDMI_NO_EXTRA_NULL_PACKET_FILLED_MASK 0x8
@@ -9626,6 +9628,10 @@
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEL__SHIFT 0x4
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED_MASK 0x7fffff00
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED__SHIFT 0x8
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE_MASK 0x10
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE__SHIFT 0x4
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT_MASK 0x3ff00
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT__SHIFT 0x8
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_LOAD_BS_COUNT_MASK 0x3ff
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_LOAD_BS_COUNT__SHIFT 0x0
#define DP_DPHY_BS_SR_SWAP_CNTL__DPHY_BS_SR_SWAP_DONE_MASK 0x8000
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h
index d3ccf5a86de0..93d84a475134 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h
@@ -3920,6 +3920,14 @@
#define mmDP4_DP_DPHY_PRBS_CNTL 0x48d4
#define mmDP5_DP_DPHY_PRBS_CNTL 0x4bd4
#define mmDP6_DP_DPHY_PRBS_CNTL 0x4ed4
+#define mmDP_DPHY_SCRAM_CNTL 0x1cd5
+#define mmDP0_DP_DPHY_SCRAM_CNTL 0x1cd5
+#define mmDP1_DP_DPHY_SCRAM_CNTL 0x1fd5
+#define mmDP2_DP_DPHY_SCRAM_CNTL 0x42d5
+#define mmDP3_DP_DPHY_SCRAM_CNTL 0x45d5
+#define mmDP4_DP_DPHY_SCRAM_CNTL 0x48d5
+#define mmDP5_DP_DPHY_SCRAM_CNTL 0x4bd5
+#define mmDP6_DP_DPHY_SCRAM_CNTL 0x4ed5
#define mmDP_DPHY_CRC_EN 0x1cd6
#define mmDP0_DP_DPHY_CRC_EN 0x1cd6
#define mmDP1_DP_DPHY_CRC_EN 0x1fd6
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h
index c331c9fe7b81..9b6825b74cc1 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h
@@ -9214,6 +9214,10 @@
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEL__SHIFT 0x4
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED_MASK 0x7fffff00
#define DP_DPHY_PRBS_CNTL__DPHY_PRBS_SEED__SHIFT 0x8
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE_MASK 0x10
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_ADVANCE__SHIFT 0x4
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT_MASK 0x3ff00
+#define DP_DPHY_SCRAM_CNTL__DPHY_SCRAMBLER_BS_COUNT__SHIFT 0x8
#define DP_DPHY_CRC_EN__DPHY_CRC_EN_MASK 0x1
#define DP_DPHY_CRC_EN__DPHY_CRC_EN__SHIFT 0x0
#define DP_DPHY_CRC_EN__DPHY_CRC_CONT_EN_MASK 0x10
diff --git a/drivers/gpu/drm/amd/include/asic_reg/si/si_reg.h b/drivers/gpu/drm/amd/include/asic_reg/si/si_reg.h
deleted file mode 100644
index 895c8e2353e3..000000000000
--- a/drivers/gpu/drm/amd/include/asic_reg/si/si_reg.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2010 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Alex Deucher
- */
-#ifndef __SI_REG_H__
-#define __SI_REG_H__
-
-/* SI */
-#define SI_DC_GPIO_HPD_MASK 0x196c
-#define SI_DC_GPIO_HPD_A 0x196d
-#define SI_DC_GPIO_HPD_EN 0x196e
-#define SI_DC_GPIO_HPD_Y 0x196f
-
-#define SI_GRPH_CONTROL 0x1a01
-# define SI_GRPH_DEPTH(x) (((x) & 0x3) << 0)
-# define SI_GRPH_DEPTH_8BPP 0
-# define SI_GRPH_DEPTH_16BPP 1
-# define SI_GRPH_DEPTH_32BPP 2
-# define SI_GRPH_NUM_BANKS(x) (((x) & 0x3) << 2)
-# define SI_ADDR_SURF_2_BANK 0
-# define SI_ADDR_SURF_4_BANK 1
-# define SI_ADDR_SURF_8_BANK 2
-# define SI_ADDR_SURF_16_BANK 3
-# define SI_GRPH_Z(x) (((x) & 0x3) << 4)
-# define SI_GRPH_BANK_WIDTH(x) (((x) & 0x3) << 6)
-# define SI_ADDR_SURF_BANK_WIDTH_1 0
-# define SI_ADDR_SURF_BANK_WIDTH_2 1
-# define SI_ADDR_SURF_BANK_WIDTH_4 2
-# define SI_ADDR_SURF_BANK_WIDTH_8 3
-# define SI_GRPH_FORMAT(x) (((x) & 0x7) << 8)
-/* 8 BPP */
-# define SI_GRPH_FORMAT_INDEXED 0
-/* 16 BPP */
-# define SI_GRPH_FORMAT_ARGB1555 0
-# define SI_GRPH_FORMAT_ARGB565 1
-# define SI_GRPH_FORMAT_ARGB4444 2
-# define SI_GRPH_FORMAT_AI88 3
-# define SI_GRPH_FORMAT_MONO16 4
-# define SI_GRPH_FORMAT_BGRA5551 5
-/* 32 BPP */
-# define SI_GRPH_FORMAT_ARGB8888 0
-# define SI_GRPH_FORMAT_ARGB2101010 1
-# define SI_GRPH_FORMAT_32BPP_DIG 2
-# define SI_GRPH_FORMAT_8B_ARGB2101010 3
-# define SI_GRPH_FORMAT_BGRA1010102 4
-# define SI_GRPH_FORMAT_8B_BGRA1010102 5
-# define SI_GRPH_FORMAT_RGB111110 6
-# define SI_GRPH_FORMAT_BGR101111 7
-# define SI_GRPH_BANK_HEIGHT(x) (((x) & 0x3) << 11)
-# define SI_ADDR_SURF_BANK_HEIGHT_1 0
-# define SI_ADDR_SURF_BANK_HEIGHT_2 1
-# define SI_ADDR_SURF_BANK_HEIGHT_4 2
-# define SI_ADDR_SURF_BANK_HEIGHT_8 3
-# define SI_GRPH_TILE_SPLIT(x) (((x) & 0x7) << 13)
-# define SI_ADDR_SURF_TILE_SPLIT_64B 0
-# define SI_ADDR_SURF_TILE_SPLIT_128B 1
-# define SI_ADDR_SURF_TILE_SPLIT_256B 2
-# define SI_ADDR_SURF_TILE_SPLIT_512B 3
-# define SI_ADDR_SURF_TILE_SPLIT_1KB 4
-# define SI_ADDR_SURF_TILE_SPLIT_2KB 5
-# define SI_ADDR_SURF_TILE_SPLIT_4KB 6
-# define SI_GRPH_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 18)
-# define SI_ADDR_SURF_MACRO_TILE_ASPECT_1 0
-# define SI_ADDR_SURF_MACRO_TILE_ASPECT_2 1
-# define SI_ADDR_SURF_MACRO_TILE_ASPECT_4 2
-# define SI_ADDR_SURF_MACRO_TILE_ASPECT_8 3
-# define SI_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20)
-# define SI_GRPH_ARRAY_LINEAR_GENERAL 0
-# define SI_GRPH_ARRAY_LINEAR_ALIGNED 1
-# define SI_GRPH_ARRAY_1D_TILED_THIN1 2
-# define SI_GRPH_ARRAY_2D_TILED_THIN1 4
-# define SI_GRPH_PIPE_CONFIG(x) (((x) & 0x1f) << 24)
-# define SI_ADDR_SURF_P2 0
-# define SI_ADDR_SURF_P4_8x16 4
-# define SI_ADDR_SURF_P4_16x16 5
-# define SI_ADDR_SURF_P4_16x32 6
-# define SI_ADDR_SURF_P4_32x32 7
-# define SI_ADDR_SURF_P8_16x16_8x16 8
-# define SI_ADDR_SURF_P8_16x32_8x16 9
-# define SI_ADDR_SURF_P8_32x32_8x16 10
-# define SI_ADDR_SURF_P8_16x32_16x16 11
-# define SI_ADDR_SURF_P8_32x32_16x16 12
-# define SI_ADDR_SURF_P8_32x32_16x32 13
-# define SI_ADDR_SURF_P8_32x64_32x32 14
-
-#endif
diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h
index e4a1697ec1d3..1d26ae768147 100644
--- a/drivers/gpu/drm/amd/include/cgs_common.h
+++ b/drivers/gpu/drm/amd/include/cgs_common.h
@@ -622,6 +622,8 @@ typedef int (*cgs_query_system_info)(struct cgs_device *cgs_device,
typedef int (*cgs_is_virtualization_enabled_t)(void *cgs_device);
+typedef int (*cgs_enter_safe_mode)(struct cgs_device *cgs_device, bool en);
+
struct cgs_ops {
/* memory management calls (similar to KFD interface) */
cgs_gpu_mem_info_t gpu_mem_info;
@@ -674,6 +676,7 @@ struct cgs_ops {
/* get system info */
cgs_query_system_info query_system_info;
cgs_is_virtualization_enabled_t is_virtualization_enabled;
+ cgs_enter_safe_mode enter_safe_mode;
};
struct cgs_os_ops; /* To be define in OS-specific CGS header */
@@ -779,4 +782,8 @@ struct cgs_device
#define cgs_is_virtualization_enabled(cgs_device) \
CGS_CALL(is_virtualization_enabled, cgs_device)
+
+#define cgs_enter_safe_mode(cgs_device, en) \
+ CGS_CALL(enter_safe_mode, cgs_device, en)
+
#endif /* _CGS_COMMON_H */
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
index c81cf1412728..429f18b99323 100644
--- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
@@ -29,153 +30,154 @@
#include "pp_instance.h"
#include "power_state.h"
#include "eventmanager.h"
-#include "pp_debug.h"
-#define PP_CHECK(handle) \
- do { \
- if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
- return -EINVAL; \
- } while (0)
+static inline int pp_check(struct pp_instance *handle)
+{
+ if (handle == NULL || handle->pp_valid != PP_VALID)
+ return -EINVAL;
-#define PP_CHECK_HW(hwmgr) \
- do { \
- if ((hwmgr) == NULL || (hwmgr)->hwmgr_func == NULL) \
- return 0; \
- } while (0)
+ if (handle->smu_mgr == NULL || handle->smu_mgr->smumgr_funcs == NULL)
+ return -EINVAL;
+
+ if (handle->pm_en == 0)
+ return PP_DPM_DISABLED;
+
+ if (handle->hwmgr == NULL || handle->hwmgr->hwmgr_func == NULL
+ || handle->eventmgr == NULL)
+ return PP_DPM_DISABLED;
+
+ return 0;
+}
static int pp_early_init(void *handle)
{
+ int ret;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+
+ ret = smum_early_init(pp_handle);
+ if (ret)
+ return ret;
+
+ if ((pp_handle->pm_en == 0)
+ || cgs_is_virtualization_enabled(pp_handle->device))
+ return PP_DPM_DISABLED;
+
+ ret = hwmgr_early_init(pp_handle);
+ if (ret) {
+ pp_handle->pm_en = 0;
+ return PP_DPM_DISABLED;
+ }
+
+ ret = eventmgr_early_init(pp_handle);
+ if (ret) {
+ kfree(pp_handle->hwmgr);
+ pp_handle->hwmgr = NULL;
+ pp_handle->pm_en = 0;
+ return PP_DPM_DISABLED;
+ }
+
return 0;
}
static int pp_sw_init(void *handle)
{
- struct pp_instance *pp_handle;
- struct pp_hwmgr *hwmgr;
+ struct pp_smumgr *smumgr;
int ret = 0;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
- if (handle == NULL)
- return -EINVAL;
-
- pp_handle = (struct pp_instance *)handle;
- hwmgr = pp_handle->hwmgr;
-
- PP_CHECK_HW(hwmgr);
-
- if (hwmgr->pptable_func == NULL ||
- hwmgr->pptable_func->pptable_init == NULL ||
- hwmgr->hwmgr_func->backend_init == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- ret = hwmgr->pptable_func->pptable_init(hwmgr);
- if (ret)
- goto err;
+ if (ret == 0 || ret == PP_DPM_DISABLED) {
+ smumgr = pp_handle->smu_mgr;
- ret = hwmgr->hwmgr_func->backend_init(hwmgr);
- if (ret)
- goto err1;
+ if (smumgr->smumgr_funcs->smu_init == NULL)
+ return -EINVAL;
- pr_info("amdgpu: powerplay initialized\n");
+ ret = smumgr->smumgr_funcs->smu_init(smumgr);
- return 0;
-err1:
- if (hwmgr->pptable_func->pptable_fini)
- hwmgr->pptable_func->pptable_fini(hwmgr);
-err:
- pr_err("amdgpu: powerplay initialization failed\n");
+ pr_info("amdgpu: powerplay sw initialized\n");
+ }
return ret;
}
static int pp_sw_fini(void *handle)
{
- struct pp_instance *pp_handle;
- struct pp_hwmgr *hwmgr;
+ struct pp_smumgr *smumgr;
int ret = 0;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
+ if (ret == 0 || ret == PP_DPM_DISABLED) {
+ smumgr = pp_handle->smu_mgr;
- pp_handle = (struct pp_instance *)handle;
- hwmgr = pp_handle->hwmgr;
-
- PP_CHECK_HW(hwmgr);
-
- if (hwmgr->hwmgr_func->backend_fini != NULL)
- ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
-
- if (hwmgr->pptable_func->pptable_fini)
- hwmgr->pptable_func->pptable_fini(hwmgr);
+ if (smumgr->smumgr_funcs->smu_fini == NULL)
+ return -EINVAL;
+ ret = smumgr->smumgr_funcs->smu_fini(smumgr);
+ }
return ret;
}
static int pp_hw_init(void *handle)
{
- struct pp_instance *pp_handle;
struct pp_smumgr *smumgr;
struct pp_eventmgr *eventmgr;
- struct pp_hwmgr *hwmgr;
int ret = 0;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- pp_handle = (struct pp_instance *)handle;
- smumgr = pp_handle->smu_mgr;
- hwmgr = pp_handle->hwmgr;
+ if (ret == 0 || ret == PP_DPM_DISABLED) {
+ smumgr = pp_handle->smu_mgr;
- if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
- smumgr->smumgr_funcs->smu_init == NULL ||
- smumgr->smumgr_funcs->start_smu == NULL)
- return -EINVAL;
-
- ret = smumgr->smumgr_funcs->smu_init(smumgr);
- if (ret) {
- printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
- return ret;
- }
+ if (smumgr->smumgr_funcs->start_smu == NULL)
+ return -EINVAL;
- ret = smumgr->smumgr_funcs->start_smu(smumgr);
- if (ret) {
- printk(KERN_ERR "[ powerplay ] smc start failed\n");
- smumgr->smumgr_funcs->smu_fini(smumgr);
- return ret;
+ if(smumgr->smumgr_funcs->start_smu(smumgr)) {
+ pr_err("smc start failed\n");
+ smumgr->smumgr_funcs->smu_fini(smumgr);
+ return -EINVAL;;
+ }
+ if (ret == PP_DPM_DISABLED)
+ return PP_DPM_DISABLED;
}
- PP_CHECK_HW(hwmgr);
-
- hw_init_power_state_table(hwmgr);
+ ret = hwmgr_hw_init(pp_handle);
+ if (ret)
+ goto err;
eventmgr = pp_handle->eventmgr;
- if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
- return -EINVAL;
+ if (eventmgr->pp_eventmgr_init == NULL ||
+ eventmgr->pp_eventmgr_init(eventmgr))
+ goto err;
- ret = eventmgr->pp_eventmgr_init(eventmgr);
return 0;
+err:
+ pp_handle->pm_en = 0;
+ kfree(pp_handle->eventmgr);
+ kfree(pp_handle->hwmgr);
+ pp_handle->hwmgr = NULL;
+ pp_handle->eventmgr = NULL;
+ return PP_DPM_DISABLED;
}
static int pp_hw_fini(void *handle)
{
- struct pp_instance *pp_handle;
- struct pp_smumgr *smumgr;
struct pp_eventmgr *eventmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
-
- pp_handle = (struct pp_instance *)handle;
- eventmgr = pp_handle->eventmgr;
+ ret = pp_check(pp_handle);
- if (eventmgr != NULL && eventmgr->pp_eventmgr_fini != NULL)
- eventmgr->pp_eventmgr_fini(eventmgr);
+ if (ret == 0) {
+ eventmgr = pp_handle->eventmgr;
- smumgr = pp_handle->smu_mgr;
-
- if (smumgr != NULL && smumgr->smumgr_funcs != NULL &&
- smumgr->smumgr_funcs->smu_fini != NULL)
- smumgr->smumgr_funcs->smu_fini(smumgr);
+ if (eventmgr->pp_eventmgr_fini != NULL)
+ eventmgr->pp_eventmgr_fini(eventmgr);
+ hwmgr_hw_fini(pp_handle);
+ }
return 0;
}
@@ -198,16 +200,18 @@ static int pp_sw_reset(void *handle)
int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -218,16 +222,18 @@ static int pp_set_powergating_state(void *handle,
enum amd_powergating_state state)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -238,49 +244,53 @@ static int pp_set_powergating_state(void *handle,
static int pp_suspend(void *handle)
{
- struct pp_instance *pp_handle;
struct pp_eventmgr *eventmgr;
struct pem_event_data event_data = { {0} };
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
+
+ if (ret != 0)
+ return ret;
- pp_handle = (struct pp_instance *)handle;
eventmgr = pp_handle->eventmgr;
+ pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
- if (eventmgr != NULL)
- pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
return 0;
}
static int pp_resume(void *handle)
{
- struct pp_instance *pp_handle;
struct pp_eventmgr *eventmgr;
struct pem_event_data event_data = { {0} };
struct pp_smumgr *smumgr;
- int ret;
+ int ret, ret1;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
- if (handle == NULL)
- return -EINVAL;
+ ret1 = pp_check(pp_handle);
+
+ if (ret1 != 0 && ret1 != PP_DPM_DISABLED)
+ return ret1;
- pp_handle = (struct pp_instance *)handle;
smumgr = pp_handle->smu_mgr;
- if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
- smumgr->smumgr_funcs->start_smu == NULL)
+ if (smumgr->smumgr_funcs->start_smu == NULL)
return -EINVAL;
ret = smumgr->smumgr_funcs->start_smu(smumgr);
if (ret) {
- printk(KERN_ERR "[ powerplay ] smc start failed\n");
+ pr_err("smc start failed\n");
smumgr->smumgr_funcs->smu_fini(smumgr);
return ret;
}
+ if (ret1 == PP_DPM_DISABLED)
+ return ret1;
+
eventmgr = pp_handle->eventmgr;
- if (eventmgr != NULL)
- pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
+
+ pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
return 0;
}
@@ -315,20 +325,19 @@ static int pp_dpm_fw_loading_complete(void *handle)
static int pp_dpm_force_performance_level(void *handle,
enum amd_dpm_forced_level level)
{
- struct pp_instance *pp_handle;
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- pp_handle = (struct pp_instance *)handle;
+ if (ret != 0)
+ return ret;
hwmgr = pp_handle->hwmgr;
- PP_CHECK_HW(hwmgr);
-
if (hwmgr->hwmgr_func->force_dpm_level == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -341,30 +350,34 @@ static enum amd_dpm_forced_level pp_dpm_get_performance_level(
void *handle)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
- return (((struct pp_instance *)handle)->hwmgr->dpm_level);
+ return hwmgr->dpm_level;
}
static int pp_dpm_get_sclk(void *handle, bool low)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_sclk == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -374,16 +387,18 @@ static int pp_dpm_get_sclk(void *handle, bool low)
static int pp_dpm_get_mclk(void *handle, bool low)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_mclk == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -393,16 +408,18 @@ static int pp_dpm_get_mclk(void *handle, bool low)
static int pp_dpm_powergate_vce(void *handle, bool gate)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->powergate_vce == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -412,16 +429,18 @@ static int pp_dpm_powergate_vce(void *handle, bool gate)
static int pp_dpm_powergate_uvd(void *handle, bool gate)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -446,16 +465,13 @@ static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id,
void *input, void *output)
{
int ret = 0;
- struct pp_instance *pp_handle;
struct pem_event_data data = { {0} };
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
- pp_handle = (struct pp_instance *)handle;
+ ret = pp_check(pp_handle);
- if (pp_handle == NULL)
- return -EINVAL;
-
- if (pp_handle->eventmgr == NULL)
- return 0;
+ if (ret != 0)
+ return ret;
switch (event_id) {
case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
@@ -489,13 +505,17 @@ static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
{
struct pp_hwmgr *hwmgr;
struct pp_power_state *state;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- if (hwmgr == NULL || hwmgr->current_ps == NULL)
+ hwmgr = pp_handle->hwmgr;
+
+ if (hwmgr->current_ps == NULL)
return -EINVAL;
state = hwmgr->current_ps;
@@ -518,16 +538,18 @@ static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -537,16 +559,18 @@ static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
static int pp_dpm_get_fan_control_mode(void *handle)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -556,16 +580,18 @@ static int pp_dpm_get_fan_control_mode(void *handle)
static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -575,16 +601,18 @@ static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -594,13 +622,15 @@ static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL)
return -EINVAL;
@@ -611,16 +641,18 @@ static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
static int pp_dpm_get_temperature(void *handle)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_temperature == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -632,13 +664,17 @@ static int pp_dpm_get_pp_num_states(void *handle,
{
struct pp_hwmgr *hwmgr;
int i;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
+
+ hwmgr = pp_handle->hwmgr;
- if (hwmgr == NULL || hwmgr->ps == NULL)
+ if (hwmgr->ps == NULL)
return -EINVAL;
data->nums = hwmgr->num_ps;
@@ -670,13 +706,15 @@ static int pp_dpm_get_pp_num_states(void *handle,
static int pp_dpm_get_pp_table(void *handle, char **table)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (!hwmgr->soft_pp_table)
return -EINVAL;
@@ -689,13 +727,15 @@ static int pp_dpm_get_pp_table(void *handle, char **table)
static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (!hwmgr->hardcode_pp_table) {
hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
@@ -717,16 +757,18 @@ static int pp_dpm_force_clock_level(void *handle,
enum pp_clock_type type, uint32_t mask)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->force_clock_level == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -737,16 +779,18 @@ static int pp_dpm_print_clock_levels(void *handle,
enum pp_clock_type type, char *buf)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
@@ -755,16 +799,18 @@ static int pp_dpm_print_clock_levels(void *handle,
static int pp_dpm_get_sclk_od(void *handle)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -774,16 +820,18 @@ static int pp_dpm_get_sclk_od(void *handle)
static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -793,16 +841,18 @@ static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
static int pp_dpm_get_mclk_od(void *handle)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -812,16 +862,18 @@ static int pp_dpm_get_mclk_od(void *handle)
static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -831,16 +883,18 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
static int pp_dpm_read_sensor(void *handle, int idx, int32_t *value)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (!handle)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
if (hwmgr->hwmgr_func->read_sensor == NULL) {
- printk(KERN_INFO "%s was not implemented.\n", __func__);
+ pr_info("%s was not implemented.\n", __func__);
return 0;
}
@@ -851,13 +905,18 @@ static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- if (handle) {
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ ret = pp_check(pp_handle);
- if (hwmgr && idx < hwmgr->num_vce_state_tables)
- return &hwmgr->vce_states[idx];
- }
+ if (ret != 0)
+ return NULL;
+
+ hwmgr = pp_handle->hwmgr;
+
+ if (hwmgr && idx < hwmgr->num_vce_state_tables)
+ return &hwmgr->vce_states[idx];
return NULL;
}
@@ -892,89 +951,44 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
.get_vce_clock_state = pp_dpm_get_vce_clock_state,
};
-static int amd_pp_instance_init(struct amd_pp_init *pp_init,
- struct amd_powerplay *amd_pp)
+int amd_powerplay_create(struct amd_pp_init *pp_init,
+ void **handle)
{
- int ret;
- struct pp_instance *handle;
-
- handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
- if (handle == NULL)
- return -ENOMEM;
-
- handle->pp_valid = PP_VALID;
-
- ret = smum_init(pp_init, handle);
- if (ret)
- goto fail_smum;
-
-
- amd_pp->pp_handle = handle;
+ struct pp_instance *instance;
- if ((amdgpu_dpm == 0)
- || cgs_is_virtualization_enabled(pp_init->device))
- return 0;
+ if (pp_init == NULL || handle == NULL)
+ return -EINVAL;
- ret = hwmgr_init(pp_init, handle);
- if (ret)
- goto fail_hwmgr;
+ instance = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
+ if (instance == NULL)
+ return -ENOMEM;
- ret = eventmgr_init(handle);
- if (ret)
- goto fail_eventmgr;
+ instance->pp_valid = PP_VALID;
+ instance->chip_family = pp_init->chip_family;
+ instance->chip_id = pp_init->chip_id;
+ instance->pm_en = pp_init->pm_en;
+ instance->feature_mask = pp_init->feature_mask;
+ instance->device = pp_init->device;
+ *handle = instance;
return 0;
-
-fail_eventmgr:
- hwmgr_fini(handle->hwmgr);
-fail_hwmgr:
- smum_fini(handle->smu_mgr);
-fail_smum:
- kfree(handle);
- return ret;
}
-static int amd_pp_instance_fini(void *handle)
+int amd_powerplay_destroy(void *handle)
{
struct pp_instance *instance = (struct pp_instance *)handle;
- if (instance == NULL)
- return -EINVAL;
-
- if ((amdgpu_dpm != 0)
- && !cgs_is_virtualization_enabled(instance->smu_mgr->device)) {
- eventmgr_fini(instance->eventmgr);
- hwmgr_fini(instance->hwmgr);
+ if (instance->pm_en) {
+ kfree(instance->eventmgr);
+ kfree(instance->hwmgr);
+ instance->hwmgr = NULL;
+ instance->eventmgr = NULL;
}
- smum_fini(instance->smu_mgr);
- kfree(handle);
- return 0;
-}
-
-int amd_powerplay_init(struct amd_pp_init *pp_init,
- struct amd_powerplay *amd_pp)
-{
- int ret;
-
- if (pp_init == NULL || amd_pp == NULL)
- return -EINVAL;
-
- ret = amd_pp_instance_init(pp_init, amd_pp);
-
- if (ret)
- return ret;
-
- amd_pp->ip_funcs = &pp_ip_funcs;
- amd_pp->pp_funcs = &pp_dpm_funcs;
-
- return 0;
-}
-
-int amd_powerplay_fini(void *handle)
-{
- amd_pp_instance_fini(handle);
-
+ kfree(instance->smu_mgr);
+ instance->smu_mgr = NULL;
+ kfree(instance);
+ instance = NULL;
return 0;
}
@@ -985,33 +999,25 @@ int amd_powerplay_reset(void *handle)
struct pem_event_data event_data = { {0} };
int ret;
- if (instance == NULL)
- return -EINVAL;
-
- eventmgr = instance->eventmgr;
- if (!eventmgr || !eventmgr->pp_eventmgr_fini)
- return -EINVAL;
-
- eventmgr->pp_eventmgr_fini(eventmgr);
+ if (cgs_is_virtualization_enabled(instance->smu_mgr->device))
+ return PP_DPM_DISABLED;
- ret = pp_sw_fini(handle);
- if (ret)
+ ret = pp_check(instance);
+ if (ret != 0)
return ret;
- kfree(instance->hwmgr->ps);
-
- ret = pp_sw_init(handle);
+ ret = pp_hw_fini(handle);
if (ret)
return ret;
- if ((amdgpu_dpm == 0)
- || cgs_is_virtualization_enabled(instance->smu_mgr->device))
- return 0;
+ ret = hwmgr_hw_init(instance);
+ if (ret)
+ return PP_DPM_DISABLED;
- hw_init_power_state_table(instance->hwmgr);
+ eventmgr = instance->eventmgr;
- if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
- return -EINVAL;
+ if (eventmgr->pp_eventmgr_init == NULL)
+ return PP_DPM_DISABLED;
ret = eventmgr->pp_eventmgr_init(eventmgr);
if (ret)
@@ -1026,12 +1032,15 @@ int amd_powerplay_display_configuration_change(void *handle,
const struct amd_pp_display_configuration *display_config)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- PP_CHECK((struct pp_instance *)handle);
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
phm_store_dal_configuration_data(hwmgr, display_config);
@@ -1042,15 +1051,18 @@ int amd_powerplay_get_display_power_level(void *handle,
struct amd_pp_simple_clock_info *output)
{
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- PP_CHECK((struct pp_instance *)handle);
+ ret = pp_check(pp_handle);
- if (output == NULL)
- return -EINVAL;
+ if (ret != 0)
+ return ret;
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ hwmgr = pp_handle->hwmgr;
- PP_CHECK_HW(hwmgr);
+ if (output == NULL)
+ return -EINVAL;
return phm_get_dal_power_level(hwmgr, output);
}
@@ -1058,18 +1070,18 @@ int amd_powerplay_get_display_power_level(void *handle,
int amd_powerplay_get_current_clocks(void *handle,
struct amd_pp_clock_info *clocks)
{
- struct pp_hwmgr *hwmgr;
struct amd_pp_simple_clock_info simple_clocks;
struct pp_clock_info hw_clocks;
+ struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- PP_CHECK((struct pp_instance *)handle);
-
- if (clocks == NULL)
- return -EINVAL;
+ ret = pp_check(pp_handle);
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
+ if (ret != 0)
+ return ret;
- PP_CHECK_HW(hwmgr);
+ hwmgr = pp_handle->hwmgr;
phm_get_dal_power_level(hwmgr, &simple_clocks);
@@ -1105,18 +1117,20 @@ int amd_powerplay_get_current_clocks(void *handle,
int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
{
int result = -1;
+ struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- struct pp_hwmgr *hwmgr;
+ ret = pp_check(pp_handle);
- PP_CHECK((struct pp_instance *)handle);
+ if (ret != 0)
+ return ret;
+
+ hwmgr = pp_handle->hwmgr;
if (clocks == NULL)
return -EINVAL;
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
-
- PP_CHECK_HW(hwmgr);
-
result = phm_get_clock_by_type(hwmgr, type, clocks);
return result;
@@ -1125,21 +1139,24 @@ int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, s
int amd_powerplay_get_display_mode_validation_clocks(void *handle,
struct amd_pp_simple_clock_info *clocks)
{
- int result = -1;
struct pp_hwmgr *hwmgr;
+ struct pp_instance *pp_handle = (struct pp_instance *)handle;
+ int ret = 0;
- PP_CHECK((struct pp_instance *)handle);
+ ret = pp_check(pp_handle);
- if (clocks == NULL)
- return -EINVAL;
+ if (ret != 0)
+ return ret;
+
+ hwmgr = pp_handle->hwmgr;
- hwmgr = ((struct pp_instance *)handle)->hwmgr;
- PP_CHECK_HW(hwmgr);
+ if (clocks == NULL)
+ return -EINVAL;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
- result = phm_get_max_high_clocks(hwmgr, clocks);
+ ret = phm_get_max_high_clocks(hwmgr, clocks);
- return result;
+ return ret;
}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
index d5ec8ccbe97d..a3cd230d636d 100644
--- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
@@ -151,7 +151,7 @@ static int thermal_interrupt_callback(void *private_data,
unsigned src_id, const uint32_t *iv_entry)
{
/* TO DO hanle PEM_Event_ThermalNotification (struct pp_eventmgr *)private_data*/
- printk("current thermal is out of range \n");
+ pr_info("current thermal is out of range \n");
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
index fb88e4e5d625..781e53dcf128 100644
--- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
@@ -60,9 +60,8 @@ static void pem_fini(struct pp_eventmgr *eventmgr)
pem_handle_event(eventmgr, AMD_PP_EVENT_UNINITIALIZE, &event_data);
}
-int eventmgr_init(struct pp_instance *handle)
+int eventmgr_early_init(struct pp_instance *handle)
{
- int result = 0;
struct pp_eventmgr *eventmgr;
if (handle == NULL)
@@ -79,12 +78,6 @@ int eventmgr_init(struct pp_instance *handle)
eventmgr->pp_eventmgr_init = pem_init;
eventmgr->pp_eventmgr_fini = pem_fini;
- return result;
-}
-
-int eventmgr_fini(struct pp_eventmgr *eventmgr)
-{
- kfree(eventmgr);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
index ec36c0e28388..e04216ec7ee1 100644
--- a/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
@@ -38,10 +38,13 @@
int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
{
+ if (eventmgr == NULL || eventmgr->hwmgr == NULL)
+ return -EINVAL;
+
if (pem_is_hw_access_blocked(eventmgr))
return 0;
- phm_force_dpm_levels(eventmgr->hwmgr, AMD_DPM_FORCED_LEVEL_AUTO);
+ phm_force_dpm_levels(eventmgr->hwmgr, eventmgr->hwmgr->dpm_level);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
index b0c63c5f54c9..3eccac735db3 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
@@ -200,7 +200,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
- AMD_CG_STATE_UNGATE);
+ AMD_CG_STATE_GATE);
cgs_set_powergating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
@@ -218,7 +218,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
- AMD_PG_STATE_GATE);
+ AMD_PG_STATE_UNGATE);
cz_dpm_update_vce_dpm(hwmgr);
cz_enable_disable_vce_dpm(hwmgr, true);
return 0;
@@ -240,10 +240,16 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
static const struct phm_master_table_item cz_enable_clock_power_gatings_list[] = {
/*we don't need an exit table here, because there is only D3 cold on Kv*/
- { phm_cf_want_uvd_power_gating, cz_tf_uvd_power_gating_initialize },
- { phm_cf_want_vce_power_gating, cz_tf_vce_power_gating_initialize },
+ {
+ .isFunctionNeededInRuntimeTable = phm_cf_want_uvd_power_gating,
+ .tableFunction = cz_tf_uvd_power_gating_initialize
+ },
+ {
+ .isFunctionNeededInRuntimeTable = phm_cf_want_vce_power_gating,
+ .tableFunction = cz_tf_vce_power_gating_initialize
+ },
/* to do { NULL, cz_tf_xdma_power_gating_enable }, */
- { NULL, NULL }
+ { }
};
const struct phm_master_table_header cz_phm_enable_clock_power_gatings_master = {
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
index 4b14f259a147..a4cde3d778b8 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
@@ -20,13 +20,13 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "atom-types.h"
#include "atombios.h"
#include "processpptables.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "smu/smu_8_0_d.h"
#include "smu8_fusion.h"
@@ -38,7 +38,6 @@
#include "cz_hwmgr.h"
#include "power_state.h"
#include "cz_clockpowergating.h"
-#include "pp_debug.h"
#define ixSMUSVI_NB_CURRENTVID 0xD8230044
#define CURRENT_NB_VID_MASK 0xff000000
@@ -288,7 +287,7 @@ static int cz_init_dynamic_state_adjustment_rule_settings(
kzalloc(table_size, GFP_KERNEL);
if (NULL == table_clk_vlt) {
- printk(KERN_ERR "[ powerplay ] Can not allocate memory!\n");
+ pr_err("Can not allocate memory!\n");
return -ENOMEM;
}
@@ -329,12 +328,12 @@ static int cz_get_system_info_data(struct pp_hwmgr *hwmgr)
&size, &frev, &crev);
if (crev != 9) {
- printk(KERN_ERR "[ powerplay ] Unsupported IGP table: %d %d\n", frev, crev);
+ pr_err("Unsupported IGP table: %d %d\n", frev, crev);
return -EINVAL;
}
if (info == NULL) {
- printk(KERN_ERR "[ powerplay ] Could not retrieve the Integrated System Info Table!\n");
+ pr_err("Could not retrieve the Integrated System Info Table!\n");
return -EINVAL;
}
@@ -361,7 +360,7 @@ static int cz_get_system_info_data(struct pp_hwmgr *hwmgr)
if (cz_hwmgr->sys_info.htc_tmp_lmt <=
cz_hwmgr->sys_info.htc_hyst_lmt) {
- printk(KERN_ERR "[ powerplay ] The htcTmpLmt should be larger than htcHystLmt.\n");
+ pr_err("The htcTmpLmt should be larger than htcHystLmt.\n");
return -EINVAL;
}
@@ -723,7 +722,7 @@ static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
clock = hwmgr->display_config.min_core_set_clock;
if (clock == 0)
- printk(KERN_INFO "[ powerplay ] min_core_set_clock not set\n");
+ pr_info("min_core_set_clock not set\n");
if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) {
cz_hwmgr->sclk_dpm.hard_min_clk = clock;
@@ -888,13 +887,13 @@ static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr,
}
static const struct phm_master_table_item cz_set_power_state_list[] = {
- {NULL, cz_tf_update_sclk_limit},
- {NULL, cz_tf_set_deep_sleep_sclk_threshold},
- {NULL, cz_tf_set_watermark_threshold},
- {NULL, cz_tf_set_enabled_levels},
- {NULL, cz_tf_enable_nb_dpm},
- {NULL, cz_tf_update_low_mem_pstate},
- {NULL, NULL}
+ { .tableFunction = cz_tf_update_sclk_limit },
+ { .tableFunction = cz_tf_set_deep_sleep_sclk_threshold },
+ { .tableFunction = cz_tf_set_watermark_threshold },
+ { .tableFunction = cz_tf_set_enabled_levels },
+ { .tableFunction = cz_tf_enable_nb_dpm },
+ { .tableFunction = cz_tf_update_low_mem_pstate },
+ { }
};
static const struct phm_master_table_header cz_set_power_state_master = {
@@ -904,15 +903,15 @@ static const struct phm_master_table_header cz_set_power_state_master = {
};
static const struct phm_master_table_item cz_setup_asic_list[] = {
- {NULL, cz_tf_reset_active_process_mask},
- {NULL, cz_tf_upload_pptable_to_smu},
- {NULL, cz_tf_init_sclk_limit},
- {NULL, cz_tf_init_uvd_limit},
- {NULL, cz_tf_init_vce_limit},
- {NULL, cz_tf_init_acp_limit},
- {NULL, cz_tf_init_power_gate_state},
- {NULL, cz_tf_init_sclk_threshold},
- {NULL, NULL}
+ { .tableFunction = cz_tf_reset_active_process_mask },
+ { .tableFunction = cz_tf_upload_pptable_to_smu },
+ { .tableFunction = cz_tf_init_sclk_limit },
+ { .tableFunction = cz_tf_init_uvd_limit },
+ { .tableFunction = cz_tf_init_vce_limit },
+ { .tableFunction = cz_tf_init_acp_limit },
+ { .tableFunction = cz_tf_init_power_gate_state },
+ { .tableFunction = cz_tf_init_sclk_threshold },
+ { }
};
static const struct phm_master_table_header cz_setup_asic_master = {
@@ -957,10 +956,10 @@ static int cz_tf_reset_cc6_data(struct pp_hwmgr *hwmgr,
}
static const struct phm_master_table_item cz_power_down_asic_list[] = {
- {NULL, cz_tf_power_up_display_clock_sys_pll},
- {NULL, cz_tf_clear_nb_dpm_flag},
- {NULL, cz_tf_reset_cc6_data},
- {NULL, NULL}
+ { .tableFunction = cz_tf_power_up_display_clock_sys_pll },
+ { .tableFunction = cz_tf_clear_nb_dpm_flag },
+ { .tableFunction = cz_tf_reset_cc6_data },
+ { }
};
static const struct phm_master_table_header cz_power_down_asic_master = {
@@ -1068,8 +1067,8 @@ static int cz_tf_check_for_dpm_enabled(struct pp_hwmgr *hwmgr,
}
static const struct phm_master_table_item cz_disable_dpm_list[] = {
- { NULL, cz_tf_check_for_dpm_enabled},
- {NULL, NULL},
+ { .tableFunction = cz_tf_check_for_dpm_enabled },
+ { },
};
@@ -1080,13 +1079,13 @@ static const struct phm_master_table_header cz_disable_dpm_master = {
};
static const struct phm_master_table_item cz_enable_dpm_list[] = {
- { NULL, cz_tf_check_for_dpm_disabled },
- { NULL, cz_tf_program_voting_clients },
- { NULL, cz_tf_start_dpm},
- { NULL, cz_tf_program_bootup_state},
- { NULL, cz_tf_enable_didt },
- { NULL, cz_tf_reset_acp_boot_level },
- {NULL, NULL},
+ { .tableFunction = cz_tf_check_for_dpm_disabled },
+ { .tableFunction = cz_tf_program_voting_clients },
+ { .tableFunction = cz_tf_start_dpm },
+ { .tableFunction = cz_tf_program_bootup_state },
+ { .tableFunction = cz_tf_enable_didt },
+ { .tableFunction = cz_tf_reset_acp_boot_level },
+ { },
};
static const struct phm_master_table_header cz_enable_dpm_master = {
@@ -1162,13 +1161,13 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
result = cz_initialize_dpm_defaults(hwmgr);
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] cz_initialize_dpm_defaults failed\n");
+ pr_err("cz_initialize_dpm_defaults failed\n");
return result;
}
result = cz_get_system_info_data(hwmgr);
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] cz_get_system_info_data failed\n");
+ pr_err("cz_get_system_info_data failed\n");
return result;
}
@@ -1177,40 +1176,40 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
result = phm_construct_table(hwmgr, &cz_setup_asic_master,
&(hwmgr->setup_asic));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to construct setup ASIC\n");
+ pr_err("Fail to construct setup ASIC\n");
return result;
}
result = phm_construct_table(hwmgr, &cz_power_down_asic_master,
&(hwmgr->power_down_asic));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to construct power down ASIC\n");
+ pr_err("Fail to construct power down ASIC\n");
return result;
}
result = phm_construct_table(hwmgr, &cz_disable_dpm_master,
&(hwmgr->disable_dynamic_state_management));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to disable_dynamic_state\n");
+ pr_err("Fail to disable_dynamic_state\n");
return result;
}
result = phm_construct_table(hwmgr, &cz_enable_dpm_master,
&(hwmgr->enable_dynamic_state_management));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to enable_dynamic_state\n");
+ pr_err("Fail to enable_dynamic_state\n");
return result;
}
result = phm_construct_table(hwmgr, &cz_set_power_state_master,
&(hwmgr->set_power_state));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n");
+ pr_err("Fail to construct set_power_state\n");
return result;
}
hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = CZ_MAX_HARDWARE_POWERLEVELS;
result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings));
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] Fail to construct enable_clock_power_gatings\n");
+ pr_err("Fail to construct enable_clock_power_gatings\n");
return result;
}
return result;
@@ -1218,9 +1217,15 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
{
- if (hwmgr != NULL && hwmgr->backend != NULL) {
+ if (hwmgr != NULL) {
+ phm_destroy_table(hwmgr, &(hwmgr->enable_clock_power_gatings));
+ phm_destroy_table(hwmgr, &(hwmgr->set_power_state));
+ phm_destroy_table(hwmgr, &(hwmgr->enable_dynamic_state_management));
+ phm_destroy_table(hwmgr, &(hwmgr->disable_dynamic_state_management));
+ phm_destroy_table(hwmgr, &(hwmgr->power_down_asic));
+ phm_destroy_table(hwmgr, &(hwmgr->setup_asic));
kfree(hwmgr->backend);
- kfree(hwmgr);
+ hwmgr->backend = NULL;
}
return 0;
}
@@ -1402,14 +1407,22 @@ int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
cz_hwmgr->vce_dpm.hard_min_clk,
PPSMC_MSG_SetEclkHardMin));
} else {
- /*EPR# 419220 -HW limitation to to */
- cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
- smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
- PPSMC_MSG_SetEclkHardMin,
- cz_get_eclk_level(hwmgr,
- cz_hwmgr->vce_dpm.hard_min_clk,
- PPSMC_MSG_SetEclkHardMin));
-
+ /*Program HardMin based on the vce_arbiter.ecclk */
+ if (hwmgr->vce_arbiter.ecclk == 0) {
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin, 0);
+ /* disable ECLK DPM 0. Otherwise VCE could hang if
+ * switching SCLK from DPM 0 to 6/7 */
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkSoftMin, 1);
+ } else {
+ cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin,
+ cz_get_eclk_level(hwmgr,
+ cz_hwmgr->vce_dpm.hard_min_clk,
+ PPSMC_MSG_SetEclkHardMin));
+ }
}
return 0;
}
@@ -1931,7 +1944,7 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {
.read_sensor = cz_read_sensor,
};
-int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
+int cz_init_function_pointers(struct pp_hwmgr *hwmgr)
{
hwmgr->hwmgr_func = &cz_hwmgr_funcs;
hwmgr->pptable_func = &pptable_funcs;
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
index c477f1cf3f23..508b422d6159 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
@@ -316,7 +316,6 @@ struct cz_hwmgr {
struct pp_hwmgr;
-int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr);
int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr);
int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr);
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
index 71822ae73a12..bc7d8bd7e7cb 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
@@ -35,7 +35,7 @@ static int phm_run_table(struct pp_hwmgr *hwmgr,
phm_table_function *function;
if (rt_table->function_list == NULL) {
- pr_debug("[ powerplay ] this function not implement!\n");
+ pr_debug("this function not implement!\n");
return 0;
}
@@ -63,14 +63,14 @@ int phm_dispatch_table(struct pp_hwmgr *hwmgr,
void *temp_storage;
if (hwmgr == NULL || rt_table == NULL) {
- printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+ pr_err("Invalid Parameter!\n");
return -EINVAL;
}
if (0 != rt_table->storage_size) {
temp_storage = kzalloc(rt_table->storage_size, GFP_KERNEL);
if (temp_storage == NULL) {
- printk(KERN_ERR "[ powerplay ] Could not allocate table temporary storage\n");
+ pr_err("Could not allocate table temporary storage\n");
return -ENOMEM;
}
} else {
@@ -95,7 +95,7 @@ int phm_construct_table(struct pp_hwmgr *hwmgr,
phm_table_function *rtf;
if (hwmgr == NULL || master_table == NULL || rt_table == NULL) {
- printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+ pr_err("Invalid Parameter!\n");
return -EINVAL;
}
@@ -116,7 +116,7 @@ int phm_construct_table(struct pp_hwmgr *hwmgr,
for (table_item = master_table->master_list;
NULL != table_item->tableFunction; table_item++) {
if ((rtf - run_time_list) > function_count) {
- printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+ pr_err("Check function results have changed\n");
kfree(run_time_list);
return -EINVAL;
}
@@ -128,7 +128,7 @@ int phm_construct_table(struct pp_hwmgr *hwmgr,
}
if ((rtf - run_time_list) > function_count) {
- printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+ pr_err("Check function results have changed\n");
kfree(run_time_list);
return -EINVAL;
}
@@ -144,7 +144,7 @@ int phm_destroy_table(struct pp_hwmgr *hwmgr,
struct phm_runtime_table_header *rt_table)
{
if (hwmgr == NULL || rt_table == NULL) {
- printk(KERN_ERR "[ powerplay ] Invalid Parameter\n");
+ pr_err("Invalid Parameter\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
index c355a0f51663..0eb8e886bf35 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
@@ -20,11 +20,11 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/errno.h>
#include "hwmgr.h"
#include "hardwaremanager.h"
#include "power_state.h"
-#include "pp_debug.h"
#define PHM_FUNC_CHECK(hw) \
do { \
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
index dc6700aee18f..2ea9c0e78689 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
@@ -20,6 +20,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+
+#include "pp_debug.h"
#include "linux/delay.h"
#include <linux/types.h>
#include <linux/kernel.h>
@@ -29,13 +31,12 @@
#include "power_state.h"
#include "hwmgr.h"
#include "pppcielanes.h"
-#include "pp_debug.h"
#include "ppatomctrl.h"
#include "ppsmc.h"
#include "pp_acpi.h"
#include "amd_acpi.h"
-extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr);
static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr);
static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr);
@@ -49,11 +50,11 @@ uint8_t convert_to_vid(uint16_t vddc)
return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
}
-int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+int hwmgr_early_init(struct pp_instance *handle)
{
struct pp_hwmgr *hwmgr;
- if ((handle == NULL) || (pp_init == NULL))
+ if (handle == NULL)
return -EINVAL;
hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
@@ -62,19 +63,20 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
handle->hwmgr = hwmgr;
hwmgr->smumgr = handle->smu_mgr;
- hwmgr->device = pp_init->device;
- hwmgr->chip_family = pp_init->chip_family;
- hwmgr->chip_id = pp_init->chip_id;
+ hwmgr->device = handle->device;
+ hwmgr->chip_family = handle->chip_family;
+ hwmgr->chip_id = handle->chip_id;
+ hwmgr->feature_mask = handle->feature_mask;
hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
hwmgr->power_source = PP_PowerSource_AC;
hwmgr->pp_table_version = PP_TABLE_V1;
-
+ hwmgr->dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
hwmgr_init_default_caps(hwmgr);
hwmgr_set_user_specify_caps(hwmgr);
switch (hwmgr->chip_family) {
case AMDGPU_FAMILY_CZ:
- cz_hwmgr_init(hwmgr);
+ cz_init_function_pointers(hwmgr);
break;
case AMDGPU_FAMILY_VI:
switch (hwmgr->chip_id) {
@@ -95,13 +97,14 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
polaris_set_asic_special_caps(hwmgr);
hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK);
break;
default:
return -EINVAL;
}
- smu7_hwmgr_init(hwmgr);
+ smu7_init_function_pointers(hwmgr);
break;
default:
return -EINVAL;
@@ -110,28 +113,7 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
return 0;
}
-int hwmgr_fini(struct pp_hwmgr *hwmgr)
-{
- if (hwmgr == NULL || hwmgr->ps == NULL)
- return -EINVAL;
-
- /* do hwmgr finish*/
- kfree(hwmgr->hardcode_pp_table);
-
- kfree(hwmgr->backend);
-
- kfree(hwmgr->start_thermal_controller.function_list);
-
- kfree(hwmgr->set_temperature_range.function_list);
-
- kfree(hwmgr->ps);
- kfree(hwmgr->current_ps);
- kfree(hwmgr->request_ps);
- kfree(hwmgr);
- return 0;
-}
-
-int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
+static int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
{
int result;
unsigned int i;
@@ -155,12 +137,20 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
return -ENOMEM;
hwmgr->request_ps = kzalloc(size, GFP_KERNEL);
- if (hwmgr->request_ps == NULL)
+ if (hwmgr->request_ps == NULL) {
+ kfree(hwmgr->ps);
+ hwmgr->ps = NULL;
return -ENOMEM;
+ }
hwmgr->current_ps = kzalloc(size, GFP_KERNEL);
- if (hwmgr->current_ps == NULL)
+ if (hwmgr->current_ps == NULL) {
+ kfree(hwmgr->request_ps);
+ kfree(hwmgr->ps);
+ hwmgr->request_ps = NULL;
+ hwmgr->ps = NULL;
return -ENOMEM;
+ }
state = hwmgr->ps;
@@ -180,10 +170,77 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
state = (struct pp_power_state *)((unsigned long)state + size);
}
+ return 0;
+}
+static int hw_fini_power_state_table(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ kfree(hwmgr->current_ps);
+ kfree(hwmgr->request_ps);
+ kfree(hwmgr->ps);
+ hwmgr->request_ps = NULL;
+ hwmgr->ps = NULL;
+ hwmgr->current_ps = NULL;
return 0;
}
+int hwmgr_hw_init(struct pp_instance *handle)
+{
+ struct pp_hwmgr *hwmgr;
+ int ret = 0;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = handle->hwmgr;
+
+ if (hwmgr->pptable_func == NULL ||
+ hwmgr->pptable_func->pptable_init == NULL ||
+ hwmgr->hwmgr_func->backend_init == NULL)
+ return -EINVAL;
+
+ ret = hwmgr->pptable_func->pptable_init(hwmgr);
+ if (ret)
+ goto err;
+
+ ret = hwmgr->hwmgr_func->backend_init(hwmgr);
+ if (ret)
+ goto err1;
+
+ ret = hw_init_power_state_table(hwmgr);
+ if (ret)
+ goto err2;
+ return 0;
+err2:
+ if (hwmgr->hwmgr_func->backend_fini)
+ hwmgr->hwmgr_func->backend_fini(hwmgr);
+err1:
+ if (hwmgr->pptable_func->pptable_fini)
+ hwmgr->pptable_func->pptable_fini(hwmgr);
+err:
+ pr_err("amdgpu: powerplay initialization failed\n");
+ return ret;
+}
+
+int hwmgr_hw_fini(struct pp_instance *handle)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = handle->hwmgr;
+
+ if (hwmgr->hwmgr_func->backend_fini)
+ hwmgr->hwmgr_func->backend_fini(hwmgr);
+ if (hwmgr->pptable_func->pptable_fini)
+ hwmgr->pptable_func->pptable_fini(hwmgr);
+ return hw_fini_power_state_table(hwmgr);
+}
+
/**
* Returns once the part of the register indicated by the mask has
@@ -196,7 +253,7 @@ int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
uint32_t cur_value;
if (hwmgr == NULL || hwmgr->device == NULL) {
- printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ pr_err("Invalid Hardware Manager!");
return -EINVAL;
}
@@ -226,7 +283,7 @@ void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
uint32_t mask)
{
if (hwmgr == NULL || hwmgr->device == NULL) {
- printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ pr_err("Invalid Hardware Manager!");
return;
}
@@ -287,7 +344,7 @@ int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
kfree(table);
-
+ table = NULL;
return 0;
}
@@ -548,7 +605,7 @@ int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr
table_clk_vlt = kzalloc(table_size, GFP_KERNEL);
if (NULL == table_clk_vlt) {
- printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
+ pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n");
return -ENOMEM;
} else {
table_clk_vlt->count = 4;
@@ -568,21 +625,6 @@ int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr
return 0;
}
-int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
-{
- if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
- }
-
- if (NULL != hwmgr->backend) {
- kfree(hwmgr->backend);
- hwmgr->backend = NULL;
- }
-
- return 0;
-}
-
uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
{
uint32_t level = 0;
@@ -624,7 +666,7 @@ void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
return;
}
}
- printk(KERN_ERR "DAL requested level can not"
+ pr_err("DAL requested level can not"
" found a available voltage in VDDC DPM Table \n");
}
@@ -682,14 +724,14 @@ void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr)
int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr)
{
- if (amdgpu_pp_feature_mask & PP_SCLK_DEEP_SLEEP_MASK)
+ if (hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK)
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SclkDeepSleep);
else
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SclkDeepSleep);
- if (amdgpu_pp_feature_mask & PP_POWER_CONTAINMENT_MASK) {
+ if (hwmgr->feature_mask & PP_POWER_CONTAINMENT_MASK) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment);
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
@@ -700,7 +742,6 @@ int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr)
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
}
- hwmgr->feature_mask = amdgpu_pp_feature_mask;
return 0;
}
@@ -726,17 +767,10 @@ int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr)
{
- /* power tune caps Assume disabled */
+
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SQRamping);
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
- PHM_PlatformCaps_DBRamping);
- phm_cap_set(hwmgr->platform_descriptor.platformCaps,
- PHM_PlatformCaps_TDRamping);
- phm_cap_set(hwmgr->platform_descriptor.platformCaps,
- PHM_PlatformCaps_TCPRamping);
-
- phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_RegulatorHot);
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
@@ -745,9 +779,19 @@ int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr)
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TablelessHardwareInterface);
- if (hwmgr->chip_id == CHIP_POLARIS11)
+
+ if (hwmgr->chip_id != CHIP_POLARIS10)
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SPLLShutdownSupport);
+
+ if (hwmgr->chip_id != CHIP_POLARIS11) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DBRamping);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TDRamping);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TCPRamping);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
index 0894527d932f..4b0a94cc995e 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
@@ -20,13 +20,13 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/module.h>
#include <linux/slab.h>
#include "ppatomctrl.h"
#include "atombios.h"
#include "cgs_common.h"
-#include "pp_debug.h"
#include "ppevvmath.h"
#define MEM_ID_MASK 0xff000000
@@ -145,10 +145,10 @@ int atomctrl_initialize_mc_reg_table(
GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
if (module_index >= vram_info->ucNumOfVRAMModule) {
- printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+ pr_err("Invalid VramInfo table.");
result = -1;
} else if (vram_info->sHeader.ucTableFormatRevision < 2) {
- printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+ pr_err("Invalid VramInfo table.");
result = -1;
}
@@ -688,7 +688,7 @@ int atomctrl_calculate_voltage_evv_on_sclk(
fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM7), 1000);
break;
default:
- printk(KERN_ERR "DPM Level not supported\n");
+ pr_err("DPM Level not supported\n");
fPowerDPMx = Convert_ULONG_ToFraction(1);
fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM0), 1000);
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
index c45bd2560468..84f01fd33aff 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
@@ -20,13 +20,13 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/module.h>
#include <linux/slab.h>
#include "process_pptables_v1_0.h"
#include "ppatomctrl.h"
#include "atombios.h"
-#include "pp_debug.h"
#include "hwmgr.h"
#include "cgs_common.h"
#include "pptable_v1_0.h"
@@ -535,7 +535,7 @@ static int get_pcie_table(
if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
else
- printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
+ pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
Disregarding the excess entries... \n");
pcie_table->count = pcie_count;
@@ -577,7 +577,7 @@ static int get_pcie_table(
if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
else
- printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
+ pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
Disregarding the excess entries... \n");
pcie_table->count = pcie_count;
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
index a4e9cf429e62..ed6c934927fb 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
@@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -27,7 +28,6 @@
#include "processpptables.h"
#include <atom-types.h>
#include <atombios.h>
-#include "pp_debug.h"
#include "pptable.h"
#include "power_state.h"
#include "hwmgr.h"
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h
index d52a28c343e3..c96ed9ed7eaf 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h
@@ -22,7 +22,7 @@
*/
#ifndef _SMU7_CLOCK_POWER_GATING_H_
-#define _SMU7_CLOCK__POWER_GATING_H_
+#define _SMU7_CLOCK_POWER_GATING_H_
#include "smu7_hwmgr.h"
#include "pp_asicblocks.h"
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
index a74f60a575ae..0a6c833720df 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
@@ -20,13 +20,13 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <asm/div64.h>
#include "linux/delay.h"
#include "pp_acpi.h"
-#include "pp_debug.h"
#include "ppatomctrl.h"
#include "atombios.h"
#include "pptable_v1_0.h"
@@ -40,6 +40,8 @@
#include "hwmgr.h"
#include "smu7_hwmgr.h"
+#include "smu7_smumgr.h"
+#include "smu_ucode_xfer_vi.h"
#include "smu7_powertune.h"
#include "smu7_dyn_defaults.h"
#include "smu7_thermal.h"
@@ -88,6 +90,8 @@ enum DPM_EVENT_SRC {
};
static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic);
+static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, uint32_t mask);
static struct smu7_power_state *cast_phw_smu7_power_state(
struct pp_hw_power_state *hw_ps)
@@ -994,7 +998,7 @@ static int smu7_start_dpm(struct pp_hwmgr *hwmgr)
SWRST_COMMAND_1, RESETLC, 0x0);
if (smu7_enable_sclk_mclk_dpm(hwmgr)) {
- printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
+ pr_err("Failed to enable Sclk DPM and Mclk DPM!");
return -EINVAL;
}
@@ -1079,7 +1083,7 @@ static void smu7_set_dpm_event_sources(struct pp_hwmgr *hwmgr, uint32_t sources)
switch (sources) {
default:
- printk(KERN_ERR "Unknown throttling event sources.");
+ pr_err("Unknown throttling event sources.");
/* fall through */
case 0:
protection = false;
@@ -1292,6 +1296,10 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE((tmp_result == 0),
"Failed to disable SMC CAC!", result = tmp_result);
+ tmp_result = smu7_disable_didt_config(hwmgr);
+ PP_ASSERT_WITH_CODE((tmp_result == 0),
+ "Failed to disable DIDT!", result = tmp_result);
+
PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_SPLL_SPREAD_SPECTRUM, SSEN, 0);
PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
@@ -1499,7 +1507,7 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
data->vddcgfx_leakage.count++;
}
} else {
- printk("Error retrieving EVV voltage value!\n");
+ pr_info("Error retrieving EVV voltage value!\n");
}
}
} else {
@@ -1527,7 +1535,7 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
if (vddc >= 2000 || vddc == 0)
return -EINVAL;
} else {
- printk(KERN_WARNING "failed to retrieving EVV voltage!\n");
+ pr_warning("failed to retrieving EVV voltage!\n");
continue;
}
@@ -1567,7 +1575,7 @@ static void smu7_patch_ppt_v1_with_vdd_leakage(struct pp_hwmgr *hwmgr,
}
if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
- printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+ pr_err("Voltage value looks like a Leakage ID but it's not patched \n");
}
/**
@@ -2032,7 +2040,7 @@ static void smu7_patch_ppt_v0_with_vdd_leakage(struct pp_hwmgr *hwmgr,
}
if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
- printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+ pr_err("Voltage value looks like a Leakage ID but it's not patched \n");
}
@@ -2267,6 +2275,21 @@ static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr)
return 0;
}
+static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+ if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
+ kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ }
+ pp_smu7_thermal_fini(hwmgr);
+ if (NULL != hwmgr->backend) {
+ kfree(hwmgr->backend);
+ hwmgr->backend = NULL;
+ }
+
+ return 0;
+}
+
static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
{
struct smu7_hwmgr *data;
@@ -2277,6 +2300,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
return -ENOMEM;
hwmgr->backend = data;
+ pp_smu7_thermal_initialize(hwmgr);
smu7_patch_voltage_workaround(hwmgr);
smu7_init_dpm_defaults(hwmgr);
@@ -2285,7 +2309,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
result = smu7_get_evv_voltages(hwmgr);
if (result) {
- printk("Get EVV Voltage Failed. Abort Driver loading!\n");
+ pr_info("Get EVV Voltage Failed. Abort Driver loading!\n");
return -EINVAL;
}
@@ -2334,7 +2358,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
smu7_thermal_parameter_init(hwmgr);
} else {
/* Ignore return value in here, we are cleaning up a mess. */
- phm_hwmgr_backend_fini(hwmgr);
+ smu7_hwmgr_backend_fini(hwmgr);
}
return 0;
@@ -2466,36 +2490,155 @@ static int smu7_force_dpm_lowest(struct pp_hwmgr *hwmgr)
}
return 0;
+}
+static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
+ uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *pcie_mask)
+{
+ uint32_t percentage;
+ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+ struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table;
+ int32_t tmp_mclk;
+ int32_t tmp_sclk;
+ int32_t count;
+
+ if (golden_dpm_table->mclk_table.count < 1)
+ return -EINVAL;
+
+ percentage = 100 * golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value /
+ golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
+
+ if (golden_dpm_table->mclk_table.count == 1) {
+ percentage = 70;
+ tmp_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
+ *mclk_mask = golden_dpm_table->mclk_table.count - 1;
+ } else {
+ tmp_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 2].value;
+ *mclk_mask = golden_dpm_table->mclk_table.count - 2;
+ }
+
+ tmp_sclk = tmp_mclk * percentage / 100;
+
+ if (hwmgr->pp_table_version == PP_TABLE_V0) {
+ for (count = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
+ count >= 0; count--) {
+ if (tmp_sclk >= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk) {
+ tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk;
+ *sclk_mask = count;
+ break;
+ }
+ }
+ if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
+ *sclk_mask = 0;
+
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ *sclk_mask = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
+ } else if (hwmgr->pp_table_version == PP_TABLE_V1) {
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ for (count = table_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
+ if (tmp_sclk >= table_info->vdd_dep_on_sclk->entries[count].clk) {
+ tmp_sclk = table_info->vdd_dep_on_sclk->entries[count].clk;
+ *sclk_mask = count;
+ break;
+ }
+ }
+ if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
+ *sclk_mask = 0;
+
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ *sclk_mask = table_info->vdd_dep_on_sclk->count - 1;
+ }
+
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK)
+ *mclk_mask = 0;
+ else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ *mclk_mask = golden_dpm_table->mclk_table.count - 1;
+
+ *pcie_mask = data->dpm_table.pcie_speed_table.count - 1;
+ return 0;
}
+
static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr,
enum amd_dpm_forced_level level)
{
int ret = 0;
+ uint32_t sclk_mask = 0;
+ uint32_t mclk_mask = 0;
+ uint32_t pcie_mask = 0;
+ uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
+ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
+ AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
+
+ if (level == hwmgr->dpm_level)
+ return ret;
+
+ if (!(hwmgr->dpm_level & profile_mode_mask)) {
+ /* enter profile mode, save current level, disable gfx cg*/
+ if (level & profile_mode_mask) {
+ hwmgr->saved_dpm_level = hwmgr->dpm_level;
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_GFX,
+ AMD_CG_STATE_UNGATE);
+ }
+ } else {
+ /* exit profile mode, restore level, enable gfx cg*/
+ if (!(level & profile_mode_mask)) {
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
+ level = hwmgr->saved_dpm_level;
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_GFX,
+ AMD_CG_STATE_GATE);
+ }
+ }
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
ret = smu7_force_dpm_highest(hwmgr);
if (ret)
return ret;
+ hwmgr->dpm_level = level;
break;
case AMD_DPM_FORCED_LEVEL_LOW:
ret = smu7_force_dpm_lowest(hwmgr);
if (ret)
return ret;
+ hwmgr->dpm_level = level;
break;
case AMD_DPM_FORCED_LEVEL_AUTO:
ret = smu7_unforce_dpm_levels(hwmgr);
if (ret)
return ret;
+ hwmgr->dpm_level = level;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
+ ret = smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask);
+ if (ret)
+ return ret;
+ hwmgr->dpm_level = level;
+ smu7_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask);
+ smu7_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask);
+ smu7_force_clock_level(hwmgr, PP_PCIE, 1<<pcie_mask);
+ break;
+ case AMD_DPM_FORCED_LEVEL_MANUAL:
+ hwmgr->dpm_level = level;
break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
default:
break;
}
- hwmgr->dpm_level = level;
+ if (level & (AMD_DPM_FORCED_LEVEL_PROFILE_PEAK | AMD_DPM_FORCED_LEVEL_HIGH))
+ smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
+ else
+ smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr);
- return ret;
+ return 0;
}
static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr)
@@ -2898,11 +3041,11 @@ static int smu7_get_pp_table_entry_v1(struct pp_hwmgr *hwmgr,
if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
if (dep_mclk_table->entries[0].clk !=
data->vbios_boot_state.mclk_bootup_value)
- printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+ pr_err("Single MCLK entry VDDCI/MCLK dependency table "
"does not match VBIOS boot MCLK level");
if (dep_mclk_table->entries[0].vddci !=
data->vbios_boot_state.vddci_bootup_value)
- printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+ pr_err("Single VDDCI entry VDDCI/MCLK dependency table "
"does not match VBIOS boot VDDCI level");
}
@@ -3046,11 +3189,11 @@ static int smu7_get_pp_table_entry_v0(struct pp_hwmgr *hwmgr,
if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
if (dep_mclk_table->entries[0].clk !=
data->vbios_boot_state.mclk_bootup_value)
- printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+ pr_err("Single MCLK entry VDDCI/MCLK dependency table "
"does not match VBIOS boot MCLK level");
if (dep_mclk_table->entries[0].v !=
data->vbios_boot_state.vddci_bootup_value)
- printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+ pr_err("Single VDDCI entry VDDCI/MCLK dependency table "
"does not match VBIOS boot VDDCI level");
}
@@ -3590,9 +3733,9 @@ static int smu7_notify_link_speed_change_after_state_change(
if (acpi_pcie_perf_request(hwmgr->device, request, false)) {
if (PP_PCIEGen2 == target_link_speed)
- printk("PSPP request to switch to Gen2 from Gen3 Failed!");
+ pr_info("PSPP request to switch to Gen2 from Gen3 Failed!");
else
- printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+ pr_info("PSPP request to switch to Gen1 from Gen2 Failed!");
}
}
@@ -4029,7 +4172,9 @@ static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
{
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
- if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
+ if (hwmgr->dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO |
+ AMD_DPM_FORCED_LEVEL_LOW |
+ AMD_DPM_FORCED_LEVEL_HIGH))
return -EINVAL;
switch (type) {
@@ -4324,9 +4469,35 @@ static int smu7_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type
return 0;
}
+static int smu7_request_firmware(struct pp_hwmgr *hwmgr)
+{
+ int ret;
+ struct cgs_firmware_info info = {0};
+
+ ret = cgs_get_firmware_info(hwmgr->device,
+ smu7_convert_fw_type_to_cgs(UCODE_ID_SMU),
+ &info);
+ if (ret || !info.kptr)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int smu7_release_firmware(struct pp_hwmgr *hwmgr)
+{
+ int ret;
+
+ ret = cgs_rel_firmware(hwmgr->device,
+ smu7_convert_fw_type_to_cgs(UCODE_ID_SMU));
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.backend_init = &smu7_hwmgr_backend_init,
- .backend_fini = &phm_hwmgr_backend_fini,
+ .backend_fini = &smu7_hwmgr_backend_fini,
.asic_setup = &smu7_setup_asic_task,
.dynamic_state_management_enable = &smu7_enable_dpm_tasks,
.apply_state_adjust_rules = smu7_apply_state_adjust_rules,
@@ -4371,6 +4542,8 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.get_clock_by_type = smu7_get_clock_by_type,
.read_sensor = smu7_read_sensor,
.dynamic_state_management_disable = smu7_disable_dpm_tasks,
+ .request_firmware = smu7_request_firmware,
+ .release_firmware = smu7_release_firmware,
};
uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
@@ -4390,7 +4563,7 @@ uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
return i;
}
-int smu7_hwmgr_init(struct pp_hwmgr *hwmgr)
+int smu7_init_function_pointers(struct pp_hwmgr *hwmgr)
{
int ret = 0;
@@ -4400,7 +4573,6 @@ int smu7_hwmgr_init(struct pp_hwmgr *hwmgr)
else if (hwmgr->pp_table_version == PP_TABLE_V1)
hwmgr->pptable_func = &pptable_v1_0_funcs;
- pp_smu7_thermal_initialize(hwmgr);
return ret;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
index 26477f0f09dc..3341c0fbd069 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
@@ -20,17 +20,19 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include "hwmgr.h"
#include "smumgr.h"
#include "smu7_hwmgr.h"
#include "smu7_powertune.h"
-#include "pp_debug.h"
#include "smu7_common.h"
#define VOLTAGE_SCALE 4
static uint32_t DIDTBlock_Info = SQ_IR_MASK | TCP_IR_MASK | TD_PCC_MASK;
+static uint32_t Polaris11_DIDTBlock_Info = SQ_PCC_MASK | TCP_IR_MASK | TD_PCC_MASK;
+
static const struct gpu_pt_config_reg GCCACConfig_Polaris10[] = {
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Offset Mask Shift Value Type
@@ -261,9 +263,9 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris11[] = {
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_0_MASK, DIDT_SQ_CTRL2__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x005a, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x000f, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_1_MASK, DIDT_SQ_CTRL2__UNUSED_1__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_2_MASK, DIDT_SQ_CTRL2__UNUSED_2__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
@@ -271,12 +273,12 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris11[] = {
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x0ebb, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__UNUSED_0_MASK, DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3153, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x0dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x0dde, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK, DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
@@ -284,8 +286,8 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris11[] = {
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__PHASE_OFFSET_MASK, DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
- { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0008, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0008, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__UNUSED_0_MASK, DIDT_SQ_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT0_MASK, DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT, 0x000a, GPU_CONFIGREG_DIDT_IND },
@@ -373,55 +375,160 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris11[] = {
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__UNUSED_0_MASK, DIDT_TCP_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { 0xFFFFFFFF }
+};
+
+static const struct gpu_pt_config_reg DIDTConfig_Polaris12[] = {
+/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ * Offset Mask Shift Value Type
+ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ */
+ { ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT0_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT0__SHIFT, 0x0073, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT1_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT1__SHIFT, 0x00ab, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT2_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT2__SHIFT, 0x0084, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT3_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT3__SHIFT, 0x005a, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT4_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT4__SHIFT, 0x0067, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT5_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT5__SHIFT, 0x0084, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT6_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT6__SHIFT, 0x0027, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT7_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT7__SHIFT, 0x0046, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT8_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT8__SHIFT, 0x00aa, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT9_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT9__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT10_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT10__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT11_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT11__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MIN_POWER_MASK, DIDT_SQ_CTRL1__MIN_POWER__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MAX_POWER_MASK, DIDT_SQ_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0x00ff, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_0_MASK, DIDT_TD_CTRL2__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x000f, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_1_MASK, DIDT_TD_CTRL2__UNUSED_1__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_2_MASK, DIDT_TD_CTRL2__UNUSED_2__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__UNUSED_0_MASK, DIDT_TD_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x0dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x0dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__UNUSED_0_MASK, DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__USE_REF_CLOCK_MASK, DIDT_TD_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__PHASE_OFFSET_MASK, DIDT_TD_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TD_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0008, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0008, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__UNUSED_0_MASK, DIDT_TD_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT0_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT0__SHIFT, 0x0004, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT1_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT1__SHIFT, 0x0037, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT2_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT2__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT3_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT3__SHIFT, 0x00ff, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT4_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT4__SHIFT, 0x0054, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT5_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT5__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT6_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT7_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MIN_POWER_MASK, DIDT_TCP_CTRL1__MIN_POWER__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MAX_POWER_MASK, DIDT_TCP_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__UNUSED_0_MASK, DIDT_TCP_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TCP_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_0_MASK, DIDT_TCP_CTRL2__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x0032, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_1_MASK, DIDT_TCP_CTRL2__UNUSED_1__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_2_MASK, DIDT_TCP_CTRL2__UNUSED_2__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__UNUSED_0_MASK, DIDT_TCP_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3dde, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK, DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__USE_REF_CLOCK_MASK, DIDT_TCP_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__PHASE_OFFSET_MASK, DIDT_TCP_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND },
+ { ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__UNUSED_0_MASK, DIDT_TCP_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND },
{ 0xFFFFFFFF }
};
static int smu7_enable_didt(struct pp_hwmgr *hwmgr, const bool enable)
{
-
uint32_t en = enable ? 1 : 0;
+ uint32_t block_en = 0;
int32_t result = 0;
+ uint32_t didt_block;
uint32_t data;
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping)) {
- data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0);
- data &= ~DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
- data |= ((en << DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK);
- cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0, data);
- DIDTBlock_Info &= ~SQ_Enable_MASK;
- DIDTBlock_Info |= en << SQ_Enable_SHIFT;
- }
+ if (hwmgr->chip_id == CHIP_POLARIS11)
+ didt_block = Polaris11_DIDTBlock_Info;
+ else
+ didt_block = DIDTBlock_Info;
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping)) {
- data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0);
- data &= ~DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
- data |= ((en << DIDT_DB_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK);
- cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0, data);
- DIDTBlock_Info &= ~DB_Enable_MASK;
- DIDTBlock_Info |= en << DB_Enable_SHIFT;
- }
+ block_en = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ? en : 0;
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping)) {
- data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0);
- data &= ~DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
- data |= ((en << DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK);
- cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0, data);
- DIDTBlock_Info &= ~TD_Enable_MASK;
- DIDTBlock_Info |= en << TD_Enable_SHIFT;
- }
+ data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0);
+ data &= ~DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
+ data |= ((block_en << DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0, data);
+ didt_block &= ~SQ_Enable_MASK;
+ didt_block |= block_en << SQ_Enable_SHIFT;
+
+ block_en = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping) ? en : 0;
+
+ data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0);
+ data &= ~DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
+ data |= ((block_en << DIDT_DB_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0, data);
+ didt_block &= ~DB_Enable_MASK;
+ didt_block |= block_en << DB_Enable_SHIFT;
+
+ block_en = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping) ? en : 0;
+ data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0);
+ data &= ~DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
+ data |= ((block_en << DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0, data);
+ didt_block &= ~TD_Enable_MASK;
+ didt_block |= block_en << TD_Enable_SHIFT;
+
+ block_en = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping) ? en : 0;
+
+ data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0);
+ data &= ~DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
+ data |= ((block_en << DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0, data);
+ didt_block &= ~TCP_Enable_MASK;
+ didt_block |= block_en << TCP_Enable_SHIFT;
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
- data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0);
- data &= ~DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
- data |= ((en << DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK);
- cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0, data);
- DIDTBlock_Info &= ~TCP_Enable_MASK;
- DIDTBlock_Info |= en << TCP_Enable_SHIFT;
- }
if (enable)
- result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_Didt_Block_Function, DIDTBlock_Info);
+ result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_Didt_Block_Function, didt_block);
return result;
}
@@ -498,7 +605,6 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO;
result = cgs_query_system_info(hwmgr->device, &sys_info);
-
if (result == 0)
num_se = sys_info.value;
@@ -507,7 +613,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
- /* TO DO Pre DIDT disable clock gating */
+ cgs_enter_safe_mode(hwmgr->device, true);
value = 0;
value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
for (count = 0; count < num_se; count++) {
@@ -526,6 +632,11 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
+ } else if (hwmgr->chip_id == CHIP_POLARIS12) {
+ result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11);
+ PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
+ result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris12);
+ PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
}
}
cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value2);
@@ -533,7 +644,13 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
result = smu7_enable_didt(hwmgr, true);
PP_ASSERT_WITH_CODE((result == 0), "EnableDiDt failed.", return result);
- /* TO DO Post DIDT enable clock gating */
+ if (hwmgr->chip_id == CHIP_POLARIS11) {
+ result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_EnableDpmDidt));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to enable DPM DIDT.", return result);
+ }
+ cgs_enter_safe_mode(hwmgr->device, false);
}
return 0;
@@ -547,11 +664,20 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
- /* TO DO Pre DIDT disable clock gating */
+
+ cgs_enter_safe_mode(hwmgr->device, true);
result = smu7_enable_didt(hwmgr, false);
- PP_ASSERT_WITH_CODE((result == 0), "Post DIDT enable clock gating failed.", return result);
- /* TO DO Post DIDT enable clock gating */
+ PP_ASSERT_WITH_CODE((result == 0),
+ "Post DIDT enable clock gating failed.",
+ return result);
+ if (hwmgr->chip_id == CHIP_POLARIS11) {
+ result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_DisableDpmDidt));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to disable DPM DIDT.", return result);
+ }
+ cgs_enter_safe_mode(hwmgr->device, false);
}
return 0;
@@ -651,7 +777,7 @@ int smu7_enable_power_containment(struct pp_hwmgr *hwmgr)
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
if (smu7_set_power_limit(hwmgr, default_limit))
- printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
+ pr_err("Failed to set Default Power Limit in SMC!");
}
}
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
index 29d0319b22e6..436ca5ce8248 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
@@ -506,18 +506,18 @@ static int tf_smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr,
static const struct phm_master_table_item
phm_thermal_start_thermal_controller_master_list[] = {
- {NULL, tf_smu7_thermal_initialize},
- {NULL, tf_smu7_thermal_set_temperature_range},
- {NULL, tf_smu7_thermal_enable_alert},
- {NULL, smum_thermal_avfs_enable},
+ { .tableFunction = tf_smu7_thermal_initialize },
+ { .tableFunction = tf_smu7_thermal_set_temperature_range },
+ { .tableFunction = tf_smu7_thermal_enable_alert },
+ { .tableFunction = smum_thermal_avfs_enable },
/* We should restrict performance levels to low before we halt the SMC.
* On the other hand we are still in boot state when we do this
* so it would be pointless.
* If this assumption changes we have to revisit this table.
*/
- {NULL, smum_thermal_setup_fan_table},
- {NULL, tf_smu7_thermal_start_smc_fan_control},
- {NULL, NULL}
+ { .tableFunction = smum_thermal_setup_fan_table },
+ { .tableFunction = tf_smu7_thermal_start_smc_fan_control },
+ { }
};
static const struct phm_master_table_header
@@ -529,10 +529,10 @@ phm_thermal_start_thermal_controller_master = {
static const struct phm_master_table_item
phm_thermal_set_temperature_range_master_list[] = {
- {NULL, tf_smu7_thermal_disable_alert},
- {NULL, tf_smu7_thermal_set_temperature_range},
- {NULL, tf_smu7_thermal_enable_alert},
- {NULL, NULL}
+ { .tableFunction = tf_smu7_thermal_disable_alert },
+ { .tableFunction = tf_smu7_thermal_set_temperature_range },
+ { .tableFunction = tf_smu7_thermal_enable_alert },
+ { }
};
static const struct phm_master_table_header
@@ -575,3 +575,9 @@ int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
return result;
}
+void pp_smu7_thermal_fini(struct pp_hwmgr *hwmgr)
+{
+ phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+ phm_destroy_table(hwmgr, &(hwmgr->start_thermal_controller));
+ return;
+} \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h
index 6face973be43..2ed774db42c7 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h
@@ -47,6 +47,7 @@ extern int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
extern int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
extern int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr);
+extern void pp_smu7_thermal_fini(struct pp_hwmgr *hwmgr);
extern int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
extern int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
index 3a883e6c601a..6dd5f0e9ef87 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
@@ -29,7 +29,10 @@
#include "amd_shared.h"
#include "cgs_common.h"
-extern int amdgpu_dpm;
+extern const struct amd_ip_funcs pp_ip_funcs;
+extern const struct amd_powerplay_funcs pp_dpm_funcs;
+
+#define PP_DPM_DISABLED 0xCCCC
enum amd_pp_sensors {
AMDGPU_PP_SENSOR_GFX_SCLK = 0,
@@ -135,17 +138,12 @@ enum amd_pp_event {
AMD_PP_EVENT_MAX
};
-enum amd_dpm_forced_level {
- AMD_DPM_FORCED_LEVEL_AUTO = 0,
- AMD_DPM_FORCED_LEVEL_LOW = 1,
- AMD_DPM_FORCED_LEVEL_HIGH = 2,
- AMD_DPM_FORCED_LEVEL_MANUAL = 3,
-};
-
struct amd_pp_init {
struct cgs_device *device;
uint32_t chip_family;
uint32_t chip_id;
+ bool pm_en;
+ uint32_t feature_mask;
};
enum amd_pp_display_config_type{
@@ -371,10 +369,10 @@ struct amd_powerplay {
const struct amd_powerplay_funcs *pp_funcs;
};
-int amd_powerplay_init(struct amd_pp_init *pp_init,
- struct amd_powerplay *amd_pp);
+int amd_powerplay_create(struct amd_pp_init *pp_init,
+ void **handle);
-int amd_powerplay_fini(void *handle);
+int amd_powerplay_destroy(void *handle);
int amd_powerplay_reset(void *handle);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h b/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
index d63ef83b2628..7bd8a7e57080 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
@@ -119,7 +119,6 @@ struct pp_eventmgr {
void (*pp_eventmgr_fini)(struct pp_eventmgr *eventmgr);
};
-int eventmgr_init(struct pp_instance *handle);
-int eventmgr_fini(struct pp_eventmgr *eventmgr);
+int eventmgr_early_init(struct pp_instance *handle);
#endif /* _EVENTMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
index 6cdb7cbf515e..7275a29293eb 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -38,8 +38,6 @@ struct pp_hwmgr;
struct phm_fan_speed_info;
struct pp_atomctrl_voltage_table;
-extern unsigned amdgpu_pp_feature_mask;
-
#define VOLTAGE_SCALE 4
uint8_t convert_to_vid(uint16_t vddc);
@@ -358,6 +356,8 @@ struct pp_hwmgr_func {
int (*get_mclk_od)(struct pp_hwmgr *hwmgr);
int (*set_mclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);
int (*read_sensor)(struct pp_hwmgr *hwmgr, int idx, int32_t *value);
+ int (*request_firmware)(struct pp_hwmgr *hwmgr);
+ int (*release_firmware)(struct pp_hwmgr *hwmgr);
};
struct pp_table_func {
@@ -612,6 +612,7 @@ struct pp_hwmgr {
uint32_t num_vce_state_tables;
enum amd_dpm_forced_level dpm_level;
+ enum amd_dpm_forced_level saved_dpm_level;
bool block_hw_access;
struct phm_gfx_arbiter gfx_arbiter;
struct phm_acp_arbiter acp_arbiter;
@@ -651,19 +652,12 @@ struct pp_hwmgr {
uint32_t feature_mask;
};
-
-extern int hwmgr_init(struct amd_pp_init *pp_init,
- struct pp_instance *handle);
-
-extern int hwmgr_fini(struct pp_hwmgr *hwmgr);
-
-extern int hw_init_power_state_table(struct pp_hwmgr *hwmgr);
-
+extern int hwmgr_early_init(struct pp_instance *handle);
+extern int hwmgr_hw_init(struct pp_instance *handle);
+extern int hwmgr_hw_fini(struct pp_instance *handle);
extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
uint32_t value, uint32_t mask);
-
-
extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
uint32_t indirect_port,
uint32_t index,
@@ -692,11 +686,10 @@ extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level
extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table,
uint16_t virtual_voltage_id, int32_t *sclk);
extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
-extern int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
-extern int smu7_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr);
extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
uint32_t sclk, uint16_t id, uint16_t *voltage);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h b/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
index bfdbec10cdd5..072880130cfb 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
@@ -24,6 +24,12 @@
#ifndef PP_DEBUG_H
#define PP_DEBUG_H
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+
+#define pr_fmt(fmt) "amdgpu: [powerplay] " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -31,7 +37,7 @@
#define PP_ASSERT_WITH_CODE(cond, msg, code) \
do { \
if (!(cond)) { \
- printk("%s\n", msg); \
+ pr_warning("%s\n", msg); \
code; \
} \
} while (0)
@@ -39,7 +45,7 @@
#define PP_DBG_LOG(fmt, ...) \
do { \
- if(0)printk(KERN_INFO "[ pp_dbg ] " fmt, ##__VA_ARGS__); \
+ pr_debug(fmt, ##__VA_ARGS__); \
} while (0)
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
index 4d8ed1f33de4..ab8494fb5c6b 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
@@ -31,6 +31,11 @@
struct pp_instance {
uint32_t pp_valid;
+ uint32_t chip_family;
+ uint32_t chip_id;
+ bool pm_en;
+ uint32_t feature_mask;
+ void *device;
struct pp_smumgr *smu_mgr;
struct pp_hwmgr *hwmgr;
struct pp_eventmgr *eventmgr;
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h
index bce00096d80d..fbc504c70b8b 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h
@@ -394,6 +394,9 @@ typedef uint16_t PPSMC_Result;
#define PPSMC_MSG_SetVBITimeout ((uint16_t) 0x306)
+#define PPSMC_MSG_EnableDpmDidt ((uint16_t) 0x309)
+#define PPSMC_MSG_DisableDpmDidt ((uint16_t) 0x30A)
+
#define PPSMC_MSG_SecureSRBMWrite ((uint16_t) 0x600)
#define PPSMC_MSG_SecureSRBMRead ((uint16_t) 0x601)
#define PPSMC_MSG_SetAddress ((uint16_t) 0x800)
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
index 2139072065cc..9b6531bd6350 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
@@ -33,6 +33,12 @@ struct pp_hwmgr;
#define smu_lower_32_bits(n) ((uint32_t)(n))
#define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16))
+extern const struct pp_smumgr_func cz_smu_funcs;
+extern const struct pp_smumgr_func iceland_smu_funcs;
+extern const struct pp_smumgr_func tonga_smu_funcs;
+extern const struct pp_smumgr_func fiji_smu_funcs;
+extern const struct pp_smumgr_func polaris10_smu_funcs;
+
enum AVFS_BTC_STATUS {
AVFS_BTC_BOOT = 0,
AVFS_BTC_BOOT_STARTEDSMU,
@@ -133,11 +139,7 @@ struct pp_smumgr {
const struct pp_smumgr_func *smumgr_funcs;
};
-
-extern int smum_init(struct amd_pp_init *pp_init,
- struct pp_instance *handle);
-
-extern int smum_fini(struct pp_smumgr *smumgr);
+extern int smum_early_init(struct pp_instance *handle);
extern int smum_get_argument(struct pp_smumgr *smumgr);
@@ -172,13 +174,6 @@ extern int smu_allocate_memory(void *device, uint32_t size,
void **kptr, void *handle);
extern int smu_free_memory(void *device, void *handle);
-
-extern int cz_smum_init(struct pp_smumgr *smumgr);
-extern int iceland_smum_init(struct pp_smumgr *smumgr);
-extern int tonga_smum_init(struct pp_smumgr *smumgr);
-extern int fiji_smum_init(struct pp_smumgr *smumgr);
-extern int polaris10_smum_init(struct pp_smumgr *smumgr);
-
extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr);
extern int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
index 5a44485526d2..1f6744a443d4 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
@@ -70,7 +70,7 @@ static int cz_send_msg_to_smc_async(struct pp_smumgr *smumgr,
result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
if (result != 0) {
- printk(KERN_ERR "[ powerplay ] cz_send_msg_to_smc_async failed\n");
+ pr_err("cz_send_msg_to_smc_async failed\n");
return result;
}
@@ -100,12 +100,12 @@ static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
return -EINVAL;
if (0 != (3 & smc_address)) {
- printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n");
+ pr_err("SMC address must be 4 byte aligned\n");
return -EINVAL;
}
if (limit <= (smc_address + 3)) {
- printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n");
+ pr_err("SMC address beyond the SMC RAM area\n");
return -EINVAL;
}
@@ -141,42 +141,6 @@ static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
return cz_send_msg_to_smc(smumgr, msg);
}
-static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
-{
- struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
- uint32_t smc_address;
-
- if (!smumgr->reload_fw) {
- printk(KERN_INFO "[ powerplay ] skip reloading...\n");
- return 0;
- }
-
- smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
- offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
-
- cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4);
-
- cz_send_msg_to_smc_with_parameter(smumgr,
- PPSMC_MSG_DriverDramAddrHi,
- cz_smu->toc_buffer.mc_addr_high);
-
- cz_send_msg_to_smc_with_parameter(smumgr,
- PPSMC_MSG_DriverDramAddrLo,
- cz_smu->toc_buffer.mc_addr_low);
-
- cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs);
-
- cz_send_msg_to_smc_with_parameter(smumgr,
- PPSMC_MSG_ExecuteJob,
- cz_smu->toc_entry_aram);
- cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
- cz_smu->toc_entry_power_profiling_index);
-
- return cz_send_msg_to_smc_with_parameter(smumgr,
- PPSMC_MSG_ExecuteJob,
- cz_smu->toc_entry_initialize_index);
-}
-
static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
uint32_t firmware)
{
@@ -198,7 +162,7 @@ static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
}
if (i >= smumgr->usec_timeout) {
- printk(KERN_ERR "[ powerplay ] SMU check loaded firmware failed.\n");
+ pr_err("SMU check loaded firmware failed.\n");
return -EINVAL;
}
@@ -250,34 +214,6 @@ static int cz_load_mec_firmware(struct pp_smumgr *smumgr)
return 0;
}
-static int cz_start_smu(struct pp_smumgr *smumgr)
-{
- int ret = 0;
- uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
- UCODE_ID_SDMA0_MASK |
- UCODE_ID_SDMA1_MASK |
- UCODE_ID_CP_CE_MASK |
- UCODE_ID_CP_ME_MASK |
- UCODE_ID_CP_PFP_MASK |
- UCODE_ID_CP_MEC_JT1_MASK |
- UCODE_ID_CP_MEC_JT2_MASK;
-
- if (smumgr->chip_id == CHIP_STONEY)
- fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
-
- ret = cz_request_smu_load_fw(smumgr);
- if (ret)
- printk(KERN_ERR "[ powerplay] SMU firmware load failed\n");
-
- cz_check_fw_load_finish(smumgr, fw_to_check);
-
- ret = cz_load_mec_firmware(smumgr);
- if (ret)
- printk(KERN_ERR "[ powerplay ] Mec Firmware load failed\n");
-
- return ret;
-}
-
static uint8_t cz_translate_firmware_enum_to_arg(struct pp_smumgr *smumgr,
enum cz_scratch_entry firmware_enum)
{
@@ -406,7 +342,7 @@ static int cz_smu_populate_single_scratch_task(
break;
if (i >= cz_smu->scratch_buffer_length) {
- printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+ pr_err("Invalid Firmware Type\n");
return -EINVAL;
}
@@ -443,7 +379,7 @@ static int cz_smu_populate_single_ucode_load_task(
break;
if (i >= cz_smu->driver_buffer_length) {
- printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+ pr_err("Invalid Firmware Type\n");
return -EINVAL;
}
@@ -729,11 +665,87 @@ static int cz_upload_pptable_settings(struct pp_smumgr *smumgr)
return 0;
}
+static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
+ uint32_t smc_address;
+
+ if (!smumgr->reload_fw) {
+ pr_info("skip reloading...\n");
+ return 0;
+ }
+
+ cz_smu_populate_firmware_entries(smumgr);
+
+ cz_smu_construct_toc(smumgr);
+
+ smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+ cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DriverDramAddrHi,
+ cz_smu->toc_buffer.mc_addr_high);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DriverDramAddrLo,
+ cz_smu->toc_buffer.mc_addr_low);
+
+ cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_aram);
+ cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_power_profiling_index);
+
+ return cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_initialize_index);
+}
+
+static int cz_start_smu(struct pp_smumgr *smumgr)
+{
+ int ret = 0;
+ uint32_t fw_to_check = 0;
+
+ fw_to_check = UCODE_ID_RLC_G_MASK |
+ UCODE_ID_SDMA0_MASK |
+ UCODE_ID_SDMA1_MASK |
+ UCODE_ID_CP_CE_MASK |
+ UCODE_ID_CP_ME_MASK |
+ UCODE_ID_CP_PFP_MASK |
+ UCODE_ID_CP_MEC_JT1_MASK |
+ UCODE_ID_CP_MEC_JT2_MASK;
+
+ if (smumgr->chip_id == CHIP_STONEY)
+ fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
+
+ ret = cz_request_smu_load_fw(smumgr);
+ if (ret)
+ pr_err("SMU firmware load failed\n");
+
+ cz_check_fw_load_finish(smumgr, fw_to_check);
+
+ ret = cz_load_mec_firmware(smumgr);
+ if (ret)
+ pr_err("Mec Firmware load failed\n");
+
+ return ret;
+}
+
static int cz_smu_init(struct pp_smumgr *smumgr)
{
- struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
uint64_t mc_addr = 0;
int ret = 0;
+ struct cz_smumgr *cz_smu;
+
+ cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL);
+ if (cz_smu == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = cz_smu;
cz_smu->toc_buffer.data_size = 4096;
cz_smu->smu_buffer.data_size =
@@ -769,12 +781,11 @@ static int cz_smu_init(struct pp_smumgr *smumgr)
cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
- cz_smu_populate_firmware_entries(smumgr);
if (0 != cz_smu_populate_single_scratch_entry(smumgr,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
- printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ pr_err("Error when Populate Firmware Entry.\n");
return -1;
}
@@ -782,14 +793,14 @@ static int cz_smu_init(struct pp_smumgr *smumgr)
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
- printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ pr_err("Error when Populate Firmware Entry.\n");
return -1;
}
if (0 != cz_smu_populate_single_scratch_entry(smumgr,
CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
- printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ pr_err("Error when Populate Firmware Entry.\n");
return -1;
}
@@ -797,7 +808,7 @@ static int cz_smu_init(struct pp_smumgr *smumgr)
CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
sizeof(struct SMU8_MultimediaPowerLogData),
&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
- printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ pr_err("Error when Populate Firmware Entry.\n");
return -1;
}
@@ -805,10 +816,9 @@ static int cz_smu_init(struct pp_smumgr *smumgr)
CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
sizeof(struct SMU8_Fusion_ClkTable),
&cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
- printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ pr_err("Error when Populate Firmware Entry.\n");
return -1;
}
- cz_smu_construct_toc(smumgr);
return 0;
}
@@ -827,13 +837,12 @@ static int cz_smu_fini(struct pp_smumgr *smumgr)
cgs_free_gpu_mem(smumgr->device,
cz_smu->smu_buffer.handle);
kfree(cz_smu);
- kfree(smumgr);
}
return 0;
}
-static const struct pp_smumgr_func cz_smu_funcs = {
+const struct pp_smumgr_func cz_smu_funcs = {
.smu_init = cz_smu_init,
.smu_fini = cz_smu_fini,
.start_smu = cz_start_smu,
@@ -847,15 +856,3 @@ static const struct pp_smumgr_func cz_smu_funcs = {
.upload_pptable_settings = cz_upload_pptable_settings,
};
-int cz_smum_init(struct pp_smumgr *smumgr)
-{
- struct cz_smumgr *cz_smu;
-
- cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL);
- if (cz_smu == NULL)
- return -ENOMEM;
-
- smumgr->backend = cz_smu;
- smumgr->smumgr_funcs = &cz_smu_funcs;
- return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
index 883818039248..7c3a290c8957 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
@@ -95,8 +95,4 @@ struct cz_smumgr {
struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH];
};
-struct pp_smumgr;
-
-extern int cz_smum_init(struct pp_smumgr *smumgr);
-
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c
index 6aeb1d20cc3b..0f7a77b7312e 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c
@@ -21,13 +21,13 @@
*
*/
+#include "pp_debug.h"
#include "fiji_smc.h"
#include "smu7_dyn_defaults.h"
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "atombios.h"
#include "fiji_smumgr.h"
@@ -2131,7 +2131,7 @@ uint32_t fiji_get_offsetof(uint32_t type, uint32_t member)
return offsetof(SMU73_Discrete_DpmTable, LowSclkInterruptThreshold);
}
}
- printk(KERN_WARNING "can't get the offset of type %x member %x\n", type, member);
+ pr_warning("can't get the offset of type %x member %x\n", type, member);
return 0;
}
@@ -2156,7 +2156,7 @@ uint32_t fiji_get_mac_definition(uint32_t value)
return SMU73_MAX_LEVELS_MVDD;
}
- printk(KERN_WARNING "can't get the mac of %x\n", value);
+ pr_warning("can't get the mac of %x\n", value);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
index 26eff56b4a99..54b347366b5d 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
@@ -21,6 +21,7 @@
*
*/
+#include "pp_debug.h"
#include "smumgr.h"
#include "smu73.h"
#include "smu_ucode_xfer_vi.h"
@@ -36,7 +37,6 @@
#include "gca/gfx_8_0_d.h"
#include "bif/bif_5_0_d.h"
#include "bif/bif_5_0_sh_mask.h"
-#include "pp_debug.h"
#include "fiji_pwrvirus.h"
#include "fiji_smc.h"
@@ -179,7 +179,7 @@ static int fiji_setup_pwr_virus(struct pp_smumgr *smumgr)
result = 0;
break;
default:
- printk(KERN_ERR "Table Exit with Invalid Command!");
+ pr_err("Table Exit with Invalid Command!");
priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL;
result = -1;
break;
@@ -202,13 +202,13 @@ static int fiji_start_avfs_btc(struct pp_smumgr *smumgr)
priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED;
result = 0;
} else {
- printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt"
+ pr_err("[AVFS][fiji_start_avfs_btc] Attempt"
" to Enable AVFS Failed!");
smum_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
result = -1;
}
} else {
- printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] "
+ pr_err("[AVFS][fiji_start_avfs_btc] "
"PerformBTC SMU msg failed");
result = -1;
}
@@ -384,7 +384,7 @@ static int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started)
case AVFS_BTC_NOTSUPPORTED: /* Do nothing */
break;
default:
- printk(KERN_ERR "[AVFS] Something is broken. See log!");
+ pr_err("[AVFS] Something is broken. See log!");
break;
}
return 0;
@@ -464,13 +464,20 @@ static bool fiji_is_hw_avfs_present(struct pp_smumgr *smumgr)
*/
static int fiji_smu_init(struct pp_smumgr *smumgr)
{
- struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
int i;
+ struct fiji_smumgr *fiji_priv = NULL;
+
+ fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
+
+ if (fiji_priv == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = fiji_priv;
if (smu7_init(smumgr))
return -EINVAL;
- priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
+ fiji_priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
if (fiji_is_hw_avfs_present(smumgr))
/* AVFS Parameter
* 0 - BTC DC disabled, BTC AC disabled
@@ -479,18 +486,18 @@ static int fiji_smu_init(struct pp_smumgr *smumgr)
* 3 - BTC DC enabled, BTC AC enabled
* Default is 0 - BTC DC disabled, BTC AC disabled
*/
- priv->avfs.AvfsBtcParam = 0;
+ fiji_priv->avfs.AvfsBtcParam = 0;
else
- priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
+ fiji_priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
- priv->activity_target[i] = 30;
+ fiji_priv->activity_target[i] = 30;
return 0;
}
-static const struct pp_smumgr_func fiji_smu_funcs = {
+const struct pp_smumgr_func fiji_smu_funcs = {
.smu_init = &fiji_smu_init,
.smu_fini = &smu7_smu_fini,
.start_smu = &fiji_start_smu,
@@ -513,18 +520,3 @@ static const struct pp_smumgr_func fiji_smu_funcs = {
.initialize_mc_reg_table = fiji_initialize_mc_reg_table,
.is_dpm_running = fiji_is_dpm_running,
};
-
-int fiji_smum_init(struct pp_smumgr *smumgr)
-{
- struct fiji_smumgr *fiji_smu = NULL;
-
- fiji_smu = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
-
- if (fiji_smu == NULL)
- return -ENOMEM;
-
- smumgr->backend = fiji_smu;
- smumgr->smumgr_funcs = &fiji_smu_funcs;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
index a24971a33bfd..ad82161df831 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
@@ -21,13 +21,13 @@
*
*/
+#include "pp_debug.h"
#include "iceland_smc.h"
#include "smu7_dyn_defaults.h"
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "atombios.h"
#include "pppcielanes.h"
@@ -1545,7 +1545,7 @@ static int iceland_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
if (0 != result) {
smu_data->smc_state_table.GraphicsBootLevel = 0;
- printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+ pr_err("VBIOS did not find boot engine clock value \
in dependency table. Using Graphics DPM level 0!");
result = 0;
}
@@ -1556,7 +1556,7 @@ static int iceland_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
if (0 != result) {
smu_data->smc_state_table.MemoryBootLevel = 0;
- printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+ pr_err("VBIOS did not find boot engine clock value \
in dependency table. Using Memory DPM level 0!");
result = 0;
}
@@ -2146,7 +2146,7 @@ uint32_t iceland_get_offsetof(uint32_t type, uint32_t member)
return offsetof(SMU71_Discrete_DpmTable, LowSclkInterruptThreshold);
}
}
- printk(KERN_WARNING "can't get the offset of type %x member %x\n", type, member);
+ pr_warning("can't get the offset of type %x member %x\n", type, member);
return 0;
}
@@ -2169,7 +2169,7 @@ uint32_t iceland_get_mac_definition(uint32_t value)
return SMU71_MAX_LEVELS_MVDD;
}
- printk(KERN_WARNING "can't get the mac of %x\n", value);
+ pr_warning("can't get the mac of %x\n", value);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c
index eeafefc4acba..0bf2def3b659 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c
@@ -22,6 +22,7 @@
* Author: Huang Rui <ray.huang@amd.com>
*
*/
+#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,7 +30,6 @@
#include "smumgr.h"
#include "iceland_smumgr.h"
-#include "pp_debug.h"
#include "smu_ucode_xfer_vi.h"
#include "ppsmc.h"
#include "smu/smu_7_1_1_d.h"
@@ -176,7 +176,7 @@ static int iceland_start_smu(struct pp_smumgr *smumgr)
return result;
if (!smu7_is_smc_ram_running(smumgr)) {
- printk("smu not running, upload firmware again \n");
+ pr_info("smu not running, upload firmware again \n");
result = iceland_smu_upload_firmware_image(smumgr);
if (result)
return result;
@@ -201,17 +201,25 @@ static int iceland_start_smu(struct pp_smumgr *smumgr)
static int iceland_smu_init(struct pp_smumgr *smumgr)
{
int i;
- struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
+ struct iceland_smumgr *iceland_priv = NULL;
+
+ iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);
+
+ if (iceland_priv == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = iceland_priv;
+
if (smu7_init(smumgr))
return -EINVAL;
for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
- smu_data->activity_target[i] = 30;
+ iceland_priv->activity_target[i] = 30;
return 0;
}
-static const struct pp_smumgr_func iceland_smu_funcs = {
+const struct pp_smumgr_func iceland_smu_funcs = {
.smu_init = &iceland_smu_init,
.smu_fini = &smu7_smu_fini,
.start_smu = &iceland_start_smu,
@@ -234,17 +242,3 @@ static const struct pp_smumgr_func iceland_smu_funcs = {
.is_dpm_running = iceland_is_dpm_running,
};
-int iceland_smum_init(struct pp_smumgr *smumgr)
-{
- struct iceland_smumgr *iceland_smu = NULL;
-
- iceland_smu = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);
-
- if (iceland_smu == NULL)
- return -ENOMEM;
-
- smumgr->backend = iceland_smu;
- smumgr->smumgr_funcs = &iceland_smu_funcs;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
index 5190e821200c..0e26900e459e 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
@@ -21,13 +21,13 @@
*
*/
+#include "pp_debug.h"
#include "polaris10_smc.h"
#include "smu7_dyn_defaults.h"
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "atombios.h"
#include "polaris10_smumgr.h"
@@ -2180,7 +2180,7 @@ uint32_t polaris10_get_offsetof(uint32_t type, uint32_t member)
return offsetof(SMU74_Discrete_DpmTable, LowSclkInterruptThreshold);
}
}
- printk(KERN_WARNING "can't get the offset of type %x member %x\n", type, member);
+ pr_warning("can't get the offset of type %x member %x\n", type, member);
return 0;
}
@@ -2207,7 +2207,7 @@ uint32_t polaris10_get_mac_definition(uint32_t value)
return SMU7_UVD_MCLK_HANDSHAKE_DISABLE;
}
- printk(KERN_WARNING "can't get the mac of %x\n", value);
+ pr_warning("can't get the mac of %x\n", value);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
index f38a68747df0..ce20ae2e520e 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
@@ -21,6 +21,7 @@
*
*/
+#include "pp_debug.h"
#include "smumgr.h"
#include "smu74.h"
#include "smu_ucode_xfer_vi.h"
@@ -36,7 +37,6 @@
#include "bif/bif_5_0_sh_mask.h"
#include "polaris10_pwrvirus.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "polaris10_smc.h"
#include "smu7_ppsmc.h"
@@ -84,7 +84,7 @@ static int polaris10_setup_pwr_virus(struct pp_smumgr *smumgr)
break;
default:
- printk("Table Exit with Invalid Command!");
+ pr_info("Table Exit with Invalid Command!");
smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL;
result = -1;
break;
@@ -102,7 +102,7 @@ static int polaris10_perform_btc(struct pp_smumgr *smumgr)
if (0 != smu_data->avfs.avfs_btc_param) {
if (0 != smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) {
- printk("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed");
+ pr_info("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed");
result = -1;
}
}
@@ -189,7 +189,7 @@ polaris10_avfs_event_mgr(struct pp_smumgr *smumgr, bool SMU_VFT_INTACT)
return -1);
if (smu_data->avfs.avfs_btc_param > 1) {
- printk("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting.");
+ pr_info("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting.");
smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL;
PP_ASSERT_WITH_CODE(-1 == polaris10_setup_pwr_virus(smumgr),
"[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ",
@@ -208,7 +208,7 @@ polaris10_avfs_event_mgr(struct pp_smumgr *smumgr, bool SMU_VFT_INTACT)
break;
default:
- printk("[AVFS] Something is broken. See log!");
+ pr_info("[AVFS] Something is broken. See log!");
break;
}
@@ -328,6 +328,7 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
/* If failed, try with different security Key. */
if (result != 0) {
smu_data->smu7_data.security_hard_key ^= 1;
+ cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
result = polaris10_start_smu_in_protection_mode(smumgr);
}
}
@@ -363,9 +364,15 @@ static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr)
static int polaris10_smu_init(struct pp_smumgr *smumgr)
{
- struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+ struct polaris10_smumgr *smu_data;
int i;
+ smu_data = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL);
+ if (smu_data == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = smu_data;
+
if (smu7_init(smumgr))
return -EINVAL;
@@ -380,7 +387,7 @@ static int polaris10_smu_init(struct pp_smumgr *smumgr)
return 0;
}
-static const struct pp_smumgr_func polaris10_smu_funcs = {
+const struct pp_smumgr_func polaris10_smu_funcs = {
.smu_init = polaris10_smu_init,
.smu_fini = smu7_smu_fini,
.start_smu = polaris10_start_smu,
@@ -403,18 +410,3 @@ static const struct pp_smumgr_func polaris10_smu_funcs = {
.get_mac_definition = polaris10_get_mac_definition,
.is_dpm_running = polaris10_is_dpm_running,
};
-
-int polaris10_smum_init(struct pp_smumgr *smumgr)
-{
- struct polaris10_smumgr *polaris10_smu = NULL;
-
- polaris10_smu = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL);
-
- if (polaris10_smu == NULL)
- return -EINVAL;
-
- smumgr->backend = polaris10_smu;
- smumgr->smumgr_funcs = &polaris10_smu_funcs;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c
index f49b5487b951..6749fbe26c74 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c
@@ -22,12 +22,12 @@
*/
+#include "pp_debug.h"
#include "smumgr.h"
#include "smu_ucode_xfer_vi.h"
#include "smu/smu_7_1_3_d.h"
#include "smu/smu_7_1_3_sh_mask.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "smu7_ppsmc.h"
#include "smu7_smumgr.h"
@@ -175,7 +175,7 @@ int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
if (ret != 1)
- printk("\n failed to send pre message %x ret is %d \n", msg, ret);
+ pr_info("\n failed to send pre message %x ret is %d \n", msg, ret);
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
@@ -184,7 +184,7 @@ int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
if (ret != 1)
- printk("\n failed to send message %x ret is %d \n", msg, ret);
+ pr_info("\n failed to send message %x ret is %d \n", msg, ret);
return 0;
}
@@ -225,7 +225,7 @@ int smu7_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP))
- printk("Failed to send Message.\n");
+ pr_info("Failed to send Message.\n");
return 0;
}
@@ -347,7 +347,7 @@ static uint32_t smu7_get_mask_for_firmware_type(uint32_t fw_type)
result = UCODE_ID_RLC_G_MASK;
break;
default:
- printk("UCode type is out of range! \n");
+ pr_info("UCode type is out of range! \n");
result = 0;
}
@@ -396,7 +396,7 @@ int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
struct SMU_DRAMData_TOC *toc;
if (!smumgr->reload_fw) {
- printk(KERN_INFO "[ powerplay ] skip reloading...\n");
+ pr_info("skip reloading...\n");
return 0;
}
@@ -474,7 +474,7 @@ int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low);
if (smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_LoadUcodes, fw_to_load))
- printk(KERN_ERR "Fail to Request SMU Load uCode");
+ pr_err("Fail to Request SMU Load uCode");
return result;
}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
index e5812aa456f3..60c36928284c 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
@@ -22,6 +22,7 @@
*/
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <drm/amdgpu_drm.h>
#include "pp_instance.h"
@@ -29,43 +30,55 @@
#include "cgs_common.h"
#include "linux/delay.h"
+MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
+MODULE_FIRMWARE("amdgpu/topaz_k_smc.bin");
+MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
+MODULE_FIRMWARE("amdgpu/tonga_k_smc.bin");
+MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
+MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_smc.bin");
-int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+
+int smum_early_init(struct pp_instance *handle)
{
struct pp_smumgr *smumgr;
- if ((handle == NULL) || (pp_init == NULL))
+ if (handle == NULL)
return -EINVAL;
smumgr = kzalloc(sizeof(struct pp_smumgr), GFP_KERNEL);
if (smumgr == NULL)
return -ENOMEM;
- smumgr->device = pp_init->device;
- smumgr->chip_family = pp_init->chip_family;
- smumgr->chip_id = pp_init->chip_id;
+ smumgr->device = handle->device;
+ smumgr->chip_family = handle->chip_family;
+ smumgr->chip_id = handle->chip_id;
smumgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
smumgr->reload_fw = 1;
handle->smu_mgr = smumgr;
switch (smumgr->chip_family) {
case AMDGPU_FAMILY_CZ:
- cz_smum_init(smumgr);
+ smumgr->smumgr_funcs = &cz_smu_funcs;
break;
case AMDGPU_FAMILY_VI:
switch (smumgr->chip_id) {
case CHIP_TOPAZ:
- iceland_smum_init(smumgr);
+ smumgr->smumgr_funcs = &iceland_smu_funcs;
break;
case CHIP_TONGA:
- tonga_smum_init(smumgr);
+ smumgr->smumgr_funcs = &tonga_smu_funcs;
break;
case CHIP_FIJI:
- fiji_smum_init(smumgr);
+ smumgr->smumgr_funcs = &fiji_smu_funcs;
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
- polaris10_smum_init(smumgr);
+ case CHIP_POLARIS12:
+ smumgr->smumgr_funcs = &polaris10_smu_funcs;
break;
default:
return -EINVAL;
@@ -79,13 +92,6 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
return 0;
}
-int smum_fini(struct pp_smumgr *smumgr)
-{
- kfree(smumgr->device);
- kfree(smumgr);
- return 0;
-}
-
int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c
index 2e1493ce1bb5..331b0aba4a13 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c
@@ -21,13 +21,13 @@
*
*/
+#include "pp_debug.h"
#include "tonga_smc.h"
#include "smu7_dyn_defaults.h"
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
#include "ppatomctrl.h"
-#include "pp_debug.h"
#include "cgs_common.h"
#include "atombios.h"
#include "tonga_smumgr.h"
@@ -656,7 +656,7 @@ int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
}
} else {
if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
- printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0 !");
+ pr_err("Pcie Dpm Enablemask is 0 !");
while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
@@ -1503,7 +1503,7 @@ static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
if (result != 0) {
smu_data->smc_state_table.GraphicsBootLevel = 0;
- printk(KERN_ERR "[powerplay] VBIOS did not find boot engine "
+ pr_err("[powerplay] VBIOS did not find boot engine "
"clock value in dependency table. "
"Using Graphics DPM level 0 !");
result = 0;
@@ -1515,7 +1515,7 @@ static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
if (result != 0) {
smu_data->smc_state_table.MemoryBootLevel = 0;
- printk(KERN_ERR "[powerplay] VBIOS did not find boot "
+ pr_err("[powerplay] VBIOS did not find boot "
"engine clock value in dependency table."
"Using Memory DPM level 0 !");
result = 0;
@@ -1739,7 +1739,7 @@ static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
config = VR_SVI2_PLANE_2;
table->VRConfig |= config;
} else {
- printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should "
+ pr_err("VDDC and VDDGFX should "
"be both on SVI2 control in splitted mode !\n");
}
} else {
@@ -1752,7 +1752,7 @@ static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
config = VR_SVI2_PLANE_1;
table->VRConfig |= config;
} else {
- printk(KERN_ERR "[ powerplay ] VDDC should be on "
+ pr_err("VDDC should be on "
"SVI2 control in merged mode !\n");
}
}
@@ -2657,7 +2657,7 @@ uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)
return offsetof(SMU72_Discrete_DpmTable, LowSclkInterruptThreshold);
}
}
- printk(KERN_WARNING "can't get the offset of type %x member %x\n", type, member);
+ pr_warning("can't get the offset of type %x member %x\n", type, member);
return 0;
}
@@ -2681,7 +2681,7 @@ uint32_t tonga_get_mac_definition(uint32_t value)
case SMU_MAX_LEVELS_MVDD:
return SMU72_MAX_LEVELS_MVDD;
}
- printk(KERN_WARNING "can't get the mac value %x\n", value);
+ pr_warning("can't get the mac value %x\n", value);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
index eff9a232e72e..a7d55366f2d2 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
@@ -20,6 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -27,7 +28,6 @@
#include "smumgr.h"
#include "tonga_smumgr.h"
-#include "pp_debug.h"
#include "smu_ucode_xfer_vi.h"
#include "tonga_ppsmc.h"
#include "smu/smu_7_1_2_d.h"
@@ -84,7 +84,7 @@ static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
/* Check pass/failed indicator */
if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) {
- printk(KERN_ERR "[ powerplay ] SMU Firmware start failed\n");
+ pr_err("SMU Firmware start failed\n");
return -EINVAL;
}
@@ -169,20 +169,25 @@ static int tonga_start_smu(struct pp_smumgr *smumgr)
*/
static int tonga_smu_init(struct pp_smumgr *smumgr)
{
- struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+ struct tonga_smumgr *tonga_priv = NULL;
+ int i;
+
+ tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
+ if (tonga_priv == NULL)
+ return -ENOMEM;
- int i;
+ smumgr->backend = tonga_priv;
if (smu7_init(smumgr))
return -EINVAL;
for (i = 0; i < SMU72_MAX_LEVELS_GRAPHICS; i++)
- smu_data->activity_target[i] = 30;
+ tonga_priv->activity_target[i] = 30;
return 0;
}
-static const struct pp_smumgr_func tonga_smu_funcs = {
+const struct pp_smumgr_func tonga_smu_funcs = {
.smu_init = &tonga_smu_init,
.smu_fini = &smu7_smu_fini,
.start_smu = &tonga_start_smu,
@@ -205,18 +210,3 @@ static const struct pp_smumgr_func tonga_smu_funcs = {
.initialize_mc_reg_table = tonga_initialize_mc_reg_table,
.is_dpm_running = tonga_is_dpm_running,
};
-
-int tonga_smum_init(struct pp_smumgr *smumgr)
-{
- struct tonga_smumgr *tonga_smu = NULL;
-
- tonga_smu = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
-
- if (tonga_smu == NULL)
- return -ENOMEM;
-
- smumgr->backend = tonga_smu;
- smumgr->smumgr_funcs = &tonga_smu_funcs;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index e5f4f4a6546d..a2e5b04cdee3 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -255,12 +255,6 @@ static int hdlcd_debugfs_init(struct drm_minor *minor)
return drm_debugfs_create_files(hdlcd_debugfs_list,
ARRAY_SIZE(hdlcd_debugfs_list), minor->debugfs_root, minor);
}
-
-static void hdlcd_debugfs_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(hdlcd_debugfs_list,
- ARRAY_SIZE(hdlcd_debugfs_list), minor);
-}
#endif
static const struct file_operations fops = {
@@ -303,7 +297,6 @@ static struct drm_driver hdlcd_driver = {
.gem_prime_mmap = drm_gem_cma_prime_mmap,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = hdlcd_debugfs_init,
- .debugfs_cleanup = hdlcd_debugfs_cleanup,
#endif
.fops = &fops,
.name = "hdlcd",
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 32f746e31379..99fb0ab39191 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -22,7 +22,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
@@ -256,6 +255,60 @@ static const struct of_device_id malidp_drm_of_match[] = {
};
MODULE_DEVICE_TABLE(of, malidp_drm_of_match);
+static bool malidp_is_compatible_hw_id(struct malidp_hw_device *hwdev,
+ const struct of_device_id *dev_id)
+{
+ u32 core_id;
+ const char *compatstr_dp500 = "arm,mali-dp500";
+ bool is_dp500;
+ bool dt_is_dp500;
+
+ /*
+ * The DP500 CORE_ID register is in a different location, so check it
+ * first. If the product id field matches, then this is DP500, otherwise
+ * check the DP550/650 CORE_ID register.
+ */
+ core_id = malidp_hw_read(hwdev, MALIDP500_DC_BASE + MALIDP_DE_CORE_ID);
+ /* Offset 0x18 will never read 0x500 on products other than DP500. */
+ is_dp500 = (MALIDP_PRODUCT_ID(core_id) == 0x500);
+ dt_is_dp500 = strnstr(dev_id->compatible, compatstr_dp500,
+ sizeof(dev_id->compatible)) != NULL;
+ if (is_dp500 != dt_is_dp500) {
+ DRM_ERROR("Device-tree expects %s, but hardware %s DP500.\n",
+ dev_id->compatible, is_dp500 ? "is" : "is not");
+ return false;
+ } else if (!dt_is_dp500) {
+ u16 product_id;
+ char buf[32];
+
+ core_id = malidp_hw_read(hwdev,
+ MALIDP550_DC_BASE + MALIDP_DE_CORE_ID);
+ product_id = MALIDP_PRODUCT_ID(core_id);
+ snprintf(buf, sizeof(buf), "arm,mali-dp%X", product_id);
+ if (!strnstr(dev_id->compatible, buf,
+ sizeof(dev_id->compatible))) {
+ DRM_ERROR("Device-tree expects %s, but hardware is DP%03X.\n",
+ dev_id->compatible, product_id);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool malidp_has_sufficient_address_space(const struct resource *res,
+ const struct of_device_id *dev_id)
+{
+ resource_size_t res_size = resource_size(res);
+ const char *compatstr_dp500 = "arm,mali-dp500";
+
+ if (!strnstr(dev_id->compatible, compatstr_dp500,
+ sizeof(dev_id->compatible)))
+ return res_size >= MALIDP550_ADDR_SPACE_SIZE;
+ else if (res_size < MALIDP500_ADDR_SPACE_SIZE)
+ return false;
+ return true;
+}
+
#define MAX_OUTPUT_CHANNELS 3
static int malidp_bind(struct device *dev)
@@ -266,6 +319,7 @@ static int malidp_bind(struct device *dev)
struct malidp_drm *malidp;
struct malidp_hw_device *hwdev;
struct platform_device *pdev = to_platform_device(dev);
+ struct of_device_id const *dev_id;
/* number of lines for the R, G and B output */
u8 output_width[MAX_OUTPUT_CHANNELS];
int ret = 0, i;
@@ -286,7 +340,6 @@ static int malidp_bind(struct device *dev)
memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
malidp->dev = hwdev;
- INIT_LIST_HEAD(&malidp->event_list);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hwdev->regs = devm_ioremap_resource(dev, res);
@@ -329,6 +382,23 @@ static int malidp_bind(struct device *dev)
clk_prepare_enable(hwdev->aclk);
clk_prepare_enable(hwdev->mclk);
+ dev_id = of_match_device(malidp_drm_of_match, dev);
+ if (!dev_id) {
+ ret = -EINVAL;
+ goto query_hw_fail;
+ }
+
+ if (!malidp_has_sufficient_address_space(res, dev_id)) {
+ DRM_ERROR("Insufficient address space in device-tree.\n");
+ ret = -EINVAL;
+ goto query_hw_fail;
+ }
+
+ if (!malidp_is_compatible_hw_id(hwdev, dev_id)) {
+ ret = -EINVAL;
+ goto query_hw_fail;
+ }
+
ret = hwdev->query_hw(hwdev);
if (ret) {
DRM_ERROR("Invalid HW configuration\n");
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index 9fc8a2e405e4..dbc617c6e4ef 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -15,12 +15,12 @@
#include <linux/mutex.h>
#include <linux/wait.h>
+#include <drm/drmP.h>
#include "malidp_hw.h"
struct malidp_drm {
struct malidp_hw_device *dev;
struct drm_fbdev_cma *fbdev;
- struct list_head event_list;
struct drm_crtc crtc;
wait_queue_head_t wq;
atomic_t config_valid;
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 4bdf531f7844..488aedf5b58d 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -21,7 +21,7 @@
#include "malidp_drv.h"
#include "malidp_hw.h"
-static const struct malidp_input_format malidp500_de_formats[] = {
+static const struct malidp_format_id malidp500_de_formats[] = {
/* fourcc, layers supporting the format, internal id */
{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 },
{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 },
@@ -69,21 +69,21 @@ static const struct malidp_input_format malidp500_de_formats[] = {
{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
-static const struct malidp_input_format malidp550_de_formats[] = {
+static const struct malidp_format_id malidp550_de_formats[] = {
MALIDP_COMMON_FORMATS,
};
static const struct malidp_layer malidp500_layers[] = {
- { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE },
- { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE },
- { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE },
+ { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
+ { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE },
+ { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE },
};
static const struct malidp_layer malidp550_layers[] = {
- { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE },
- { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE },
- { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE },
- { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE },
+ { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
+ { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE },
+ { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
+ { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, 0 },
};
#define MALIDP_DE_DEFAULT_PREFETCH_START 5
@@ -436,8 +436,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
},
- .input_formats = malidp500_de_formats,
- .n_input_formats = ARRAY_SIZE(malidp500_de_formats),
+ .pixel_formats = malidp500_de_formats,
+ .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
.bus_align_bytes = 8,
},
.query_hw = malidp500_query_hw,
@@ -447,6 +447,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.set_config_valid = malidp500_set_config_valid,
.modeset = malidp500_modeset,
.rotmem_required = malidp500_rotmem_required,
+ .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
},
[MALIDP_550] = {
.map = {
@@ -469,8 +470,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
},
- .input_formats = malidp550_de_formats,
- .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
+ .pixel_formats = malidp550_de_formats,
+ .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
.bus_align_bytes = 8,
},
.query_hw = malidp550_query_hw,
@@ -480,6 +481,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.set_config_valid = malidp550_set_config_valid,
.modeset = malidp550_modeset,
.rotmem_required = malidp550_rotmem_required,
+ .features = 0,
},
[MALIDP_650] = {
.map = {
@@ -503,8 +505,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
},
- .input_formats = malidp550_de_formats,
- .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
+ .pixel_formats = malidp550_de_formats,
+ .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
.bus_align_bytes = 16,
},
.query_hw = malidp650_query_hw,
@@ -514,6 +516,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
.set_config_valid = malidp550_set_config_valid,
.modeset = malidp550_modeset,
.rotmem_required = malidp550_rotmem_required,
+ .features = 0,
},
};
@@ -522,10 +525,10 @@ u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
{
unsigned int i;
- for (i = 0; i < map->n_input_formats; i++) {
- if (((map->input_formats[i].layer & layer_id) == layer_id) &&
- (map->input_formats[i].format == format))
- return map->input_formats[i].id;
+ for (i = 0; i < map->n_pixel_formats; i++) {
+ if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
+ (map->pixel_formats[i].format == format))
+ return map->pixel_formats[i].id;
}
return MALIDP_INVALID_FORMAT_ID;
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 087e1202db3d..00974b59407d 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -35,7 +35,7 @@ enum {
DE_SMART = BIT(4),
};
-struct malidp_input_format {
+struct malidp_format_id {
u32 format; /* DRM fourcc */
u8 layer; /* bitmask of layers supporting it */
u8 id; /* used internally */
@@ -58,6 +58,7 @@ struct malidp_layer {
u16 id; /* layer ID */
u16 base; /* address offset for the register bank */
u16 ptr; /* address offset for the pointer register */
+ u16 stride_offset; /* Offset to the first stride register. */
};
/* regmap features */
@@ -85,14 +86,18 @@ struct malidp_hw_regmap {
const struct malidp_irq_map se_irq_map;
const struct malidp_irq_map dc_irq_map;
- /* list of supported input formats for each layer */
- const struct malidp_input_format *input_formats;
- const u8 n_input_formats;
+ /* list of supported pixel formats for each layer */
+ const struct malidp_format_id *pixel_formats;
+ const u8 n_pixel_formats;
/* pitch alignment requirement in bytes */
const u8 bus_align_bytes;
};
+/* device features */
+/* Unlike DP550/650, DP500 has 3 stride registers in its video layer. */
+#define MALIDP_DEVICE_LV_HAS_3_STRIDES BIT(0)
+
struct malidp_hw_device {
const struct malidp_hw_regmap map;
void __iomem *regs;
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index eff2fe47e26a..414aada10fe5 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -11,6 +11,7 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -36,7 +37,6 @@
#define LAYER_V_VAL(x) (((x) & 0x1fff) << 16)
#define MALIDP_LAYER_COMP_SIZE 0x010
#define MALIDP_LAYER_OFFSET 0x014
-#define MALIDP_LAYER_STRIDE 0x018
/*
* This 4-entry look-up-table is used to determine the full 8-bit alpha value
@@ -67,13 +67,14 @@ drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state) {
- m_state = to_malidp_plane_state(plane->state);
- __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
- state->rotmem_size = m_state->rotmem_size;
- state->format = m_state->format;
- state->n_planes = m_state->n_planes;
- }
+ if (!state)
+ return NULL;
+
+ m_state = to_malidp_plane_state(plane->state);
+ __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+ state->rotmem_size = m_state->rotmem_size;
+ state->format = m_state->format;
+ state->n_planes = m_state->n_planes;
return &state->base;
}
@@ -102,8 +103,10 @@ static int malidp_de_plane_check(struct drm_plane *plane,
{
struct malidp_plane *mp = to_malidp_plane(plane);
struct malidp_plane_state *ms = to_malidp_plane_state(state);
+ struct drm_crtc_state *crtc_state;
struct drm_framebuffer *fb;
- int i;
+ struct drm_rect clip = { 0 };
+ int i, ret;
u32 src_w, src_h;
if (!state->crtc || !state->fb)
@@ -131,8 +134,17 @@ static int malidp_de_plane_check(struct drm_plane *plane,
if ((state->crtc_w > mp->hwdev->max_line_size) ||
(state->crtc_h > mp->hwdev->max_line_size) ||
(state->crtc_w < mp->hwdev->min_line_size) ||
- (state->crtc_h < mp->hwdev->min_line_size) ||
- (state->crtc_w != src_w) || (state->crtc_h != src_h))
+ (state->crtc_h < mp->hwdev->min_line_size))
+ return -EINVAL;
+
+ /*
+ * DP550/650 video layers can accept 3 plane formats only if
+ * fb->pitches[1] == fb->pitches[2] since they don't have a
+ * third plane stride register.
+ */
+ if (ms->n_planes == 3 &&
+ !(mp->hwdev->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) &&
+ (state->fb->pitches[1] != state->fb->pitches[2]))
return -EINVAL;
/* packed RGB888 / BGR888 can't be rotated or flipped */
@@ -141,6 +153,16 @@ static int malidp_de_plane_check(struct drm_plane *plane,
fb->format->format == DRM_FORMAT_BGR888))
return -EINVAL;
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+ ret = drm_plane_helper_check_state(state, &clip,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true, true);
+ if (ret)
+ return ret;
+
ms->rotmem_size = 0;
if (state->rotation & MALIDP_ROTATED_MASK) {
int val;
@@ -157,6 +179,25 @@ static int malidp_de_plane_check(struct drm_plane *plane,
return 0;
}
+static void malidp_de_set_plane_pitches(struct malidp_plane *mp,
+ int num_planes, unsigned int pitches[3])
+{
+ int i;
+ int num_strides = num_planes;
+
+ if (!mp->layer->stride_offset)
+ return;
+
+ if (num_planes == 3)
+ num_strides = (mp->hwdev->features &
+ MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
+
+ for (i = 0; i < num_strides; ++i)
+ malidp_hw_write(mp->hwdev, pitches[i],
+ mp->layer->base +
+ mp->layer->stride_offset + i * 4);
+}
+
static void malidp_de_plane_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -174,13 +215,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
/* convert src values from Q16 fixed point to integer */
src_w = plane->state->src_w >> 16;
src_h = plane->state->src_h >> 16;
- if (plane->state->rotation & MALIDP_ROTATED_MASK) {
- dest_w = plane->state->crtc_h;
- dest_h = plane->state->crtc_w;
- } else {
- dest_w = plane->state->crtc_w;
- dest_h = plane->state->crtc_h;
- }
+ dest_w = plane->state->crtc_w;
+ dest_h = plane->state->crtc_h;
malidp_hw_write(mp->hwdev, ms->format, mp->layer->base);
@@ -189,11 +225,12 @@ static void malidp_de_plane_update(struct drm_plane *plane,
ptr = mp->layer->ptr + (i << 4);
obj = drm_fb_cma_get_gem_obj(plane->state->fb, i);
+ obj->paddr += plane->state->fb->offsets[i];
malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr);
malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4);
- malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i],
- mp->layer->base + MALIDP_LAYER_STRIDE);
}
+ malidp_de_set_plane_pitches(mp, ms->n_planes,
+ plane->state->fb->pitches);
malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
mp->layer->base + MALIDP_LAYER_SIZE);
@@ -211,11 +248,12 @@ static void malidp_de_plane_update(struct drm_plane *plane,
/* setup the rotation and axis flip bits */
if (plane->state->rotation & DRM_ROTATE_MASK)
- val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET;
+ val |= ilog2(plane->state->rotation & DRM_ROTATE_MASK) <<
+ LAYER_ROT_OFFSET;
if (plane->state->rotation & DRM_REFLECT_X)
- val |= LAYER_V_FLIP;
- if (plane->state->rotation & DRM_REFLECT_Y)
val |= LAYER_H_FLIP;
+ if (plane->state->rotation & DRM_REFLECT_Y)
+ val |= LAYER_V_FLIP;
/*
* always enable pixel alpha blending until we have a way to change
@@ -258,7 +296,7 @@ int malidp_de_planes_init(struct drm_device *drm)
u32 *formats;
int ret, i, j, n;
- formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL);
+ formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL);
if (!formats) {
ret = -ENOMEM;
goto cleanup;
@@ -274,9 +312,9 @@ int malidp_de_planes_init(struct drm_device *drm)
}
/* build the list of DRM supported formats based on the map */
- for (n = 0, j = 0; j < map->n_input_formats; j++) {
- if ((map->input_formats[j].layer & id) == id)
- formats[n++] = map->input_formats[j].format;
+ for (n = 0, j = 0; j < map->n_pixel_formats; j++) {
+ if ((map->pixel_formats[j].layer & id) == id)
+ formats[n++] = map->pixel_formats[j].format;
}
plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 73fecb38f955..aff6d4a84e99 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -81,6 +81,10 @@
#define MALIDP_DE_SYNC_WIDTH 0x8
#define MALIDP_DE_HV_ACTIVE 0xc
+/* Stride register offsets relative to Lx_BASE */
+#define MALIDP_DE_LG_STRIDE 0x18
+#define MALIDP_DE_LV_STRIDE0 0x18
+
/* macros to set values into registers */
#define MALIDP_DE_H_FRONTPORCH(x) (((x) & 0xfff) << 0)
#define MALIDP_DE_H_BACKPORCH(x) (((x) & 0x3ff) << 16)
@@ -92,7 +96,10 @@
#define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0)
#define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16)
+#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16)
+
/* register offsets and bits specific to DP500 */
+#define MALIDP500_ADDR_SPACE_SIZE 0x01000
#define MALIDP500_DC_BASE 0x00000
#define MALIDP500_DC_CONTROL 0x0000c
#define MALIDP500_DC_CONFIG_REQ (1 << 17)
@@ -125,6 +132,7 @@
#define MALIDP500_CONFIG_ID 0x00fd4
/* register offsets and bits specific to DP550/DP650 */
+#define MALIDP550_ADDR_SPACE_SIZE 0x10000
#define MALIDP550_DE_CONTROL 0x00010
#define MALIDP550_DE_LINE_COUNTER 0x00014
#define MALIDP550_DE_AXI_CONTROL 0x00018
diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig
index 15f3ecfb16f1..eafaeeb7b5b1 100644
--- a/drivers/gpu/drm/armada/Kconfig
+++ b/drivers/gpu/drm/armada/Kconfig
@@ -1,6 +1,6 @@
config DRM_ARMADA
tristate "DRM support for Marvell Armada SoCs"
- depends on DRM && HAVE_CLK && ARM
+ depends on DRM && HAVE_CLK && ARM && MMU
select DRM_KMS_HELPER
help
Support the "LCD" controllers found on the Marvell Armada 510
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index 2a1368fac1d1..50c910efa13d 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -236,8 +236,6 @@ struct ttm_bo_driver ast_bo_driver = {
.verify_access = ast_bo_verify_access,
.io_mem_reserve = &ast_ttm_io_mem_reserve,
.io_mem_free = &ast_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int ast_mm_init(struct ast_private *ast)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index cbd0070265c9..0bf32d6ac39b 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -431,15 +431,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
- if (dc->fbdev) {
+ if (dc->fbdev)
drm_fbdev_cma_hotplug_event(dc->fbdev);
- } else {
- dc->fbdev = drm_fbdev_cma_init(dev, 24,
- dev->mode_config.num_crtc,
- dev->mode_config.num_connector);
- if (IS_ERR(dc->fbdev))
- dc->fbdev = NULL;
- }
}
struct atmel_hlcdc_dc_commit {
@@ -653,10 +646,13 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
platform_set_drvdata(pdev, dev);
- drm_kms_helper_poll_init(dev);
+ dc->fbdev = drm_fbdev_cma_init(dev, 24,
+ dev->mode_config.num_crtc,
+ dev->mode_config.num_connector);
+ if (IS_ERR(dc->fbdev))
+ dc->fbdev = NULL;
- /* force connectors detection */
- drm_helper_hpd_irq_event(dev);
+ drm_kms_helper_poll_init(dev);
return 0;
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index ceb1fecf02dd..857755ac2d70 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -205,8 +205,6 @@ struct ttm_bo_driver bochs_bo_driver = {
.verify_access = bochs_bo_verify_access,
.io_mem_reserve = &bochs_ttm_io_mem_reserve,
.io_mem_free = &bochs_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int bochs_mm_init(struct bochs_device *bochs)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 992d76ce02bb..fe18a5d2d84b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -12,6 +12,7 @@
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
@@ -317,6 +318,8 @@ struct adv7511 {
bool edid_read;
wait_queue_head_t wq;
+ struct work_struct hpd_work;
+
struct drm_bridge bridge;
struct drm_connector connector;
@@ -329,6 +332,9 @@ struct adv7511 {
struct gpio_desc *gpio_pd;
+ struct regulator_bulk_data *supplies;
+ unsigned int num_supplies;
+
/* ADV7533 DSI RX related params */
struct device_node *host_node;
struct mipi_dsi_device *dsi;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 8dba729f6ef9..f75ab6278113 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -325,7 +325,7 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
}
-static void adv7511_power_on(struct adv7511 *adv7511)
+static void __adv7511_power_on(struct adv7511 *adv7511)
{
adv7511->current_edid_segment = -1;
@@ -338,7 +338,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
* Still, let's be safe and stick to the documentation.
*/
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
- ADV7511_INT0_EDID_READY);
+ ADV7511_INT0_EDID_READY | ADV7511_INT0_HPD);
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
ADV7511_INT1_DDC_ERROR);
}
@@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511)
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7511_REG_POWER2_HPD_SRC_MASK,
ADV7511_REG_POWER2_HPD_SRC_NONE);
+}
+
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+ __adv7511_power_on(adv7511);
/*
* Most of the registers are reset during power down or when HPD is low.
@@ -362,21 +367,23 @@ static void adv7511_power_on(struct adv7511 *adv7511)
if (adv7511->type == ADV7533)
adv7533_dsi_power_on(adv7511);
-
adv7511->powered = true;
}
-static void adv7511_power_off(struct adv7511 *adv7511)
+static void __adv7511_power_off(struct adv7511 *adv7511)
{
/* TODO: setup additional power down modes */
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
ADV7511_POWER_POWER_DOWN,
ADV7511_POWER_POWER_DOWN);
regcache_mark_dirty(adv7511->regmap);
+}
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+ __adv7511_power_off(adv7511);
if (adv7511->type == ADV7533)
adv7533_dsi_power_off(adv7511);
-
adv7511->powered = false;
}
@@ -402,6 +409,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
return false;
}
+static void adv7511_hpd_work(struct work_struct *work)
+{
+ struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
+ enum drm_connector_status status;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+ if (ret < 0)
+ status = connector_status_disconnected;
+ else if (val & ADV7511_STATUS_HPD)
+ status = connector_status_connected;
+ else
+ status = connector_status_disconnected;
+
+ if (adv7511->connector.status != status) {
+ adv7511->connector.status = status;
+ drm_kms_helper_hotplug_event(adv7511->connector.dev);
+ }
+}
+
static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
{
unsigned int irq0, irq1;
@@ -419,7 +447,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
- drm_helper_hpd_irq_event(adv7511->connector.dev);
+ schedule_work(&adv7511->hpd_work);
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
adv7511->edid_read = true;
@@ -546,23 +574,20 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
/* Reading the EDID only works if the device is powered */
if (!adv7511->powered) {
- regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
- ADV7511_POWER_POWER_DOWN, 0);
- if (adv7511->i2c_main->irq) {
- regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
- ADV7511_INT0_EDID_READY);
- regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
- ADV7511_INT1_DDC_ERROR);
- }
- adv7511->current_edid_segment = -1;
+ unsigned int edid_i2c_addr =
+ (adv7511->i2c_main->addr << 1) + 4;
+
+ __adv7511_power_on(adv7511);
+
+ /* Reset the EDID_I2C_ADDR register as it might be cleared */
+ regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+ edid_i2c_addr);
}
edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
if (!adv7511->powered)
- regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
- ADV7511_POWER_POWER_DOWN,
- ADV7511_POWER_POWER_DOWN);
+ __adv7511_power_off(adv7511);
kfree(adv7511->edid);
adv7511->edid = edid;
@@ -825,6 +850,10 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
if (adv->type == ADV7533)
ret = adv7533_attach_dsi(adv);
+ if (adv->i2c_main->irq)
+ regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0),
+ ADV7511_INT0_HPD);
+
return ret;
}
@@ -839,6 +868,58 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
* Probe & remove
*/
+static const char * const adv7511_supply_names[] = {
+ "avdd",
+ "dvdd",
+ "pvdd",
+ "bgvdd",
+ "dvdd-3v",
+};
+
+static const char * const adv7533_supply_names[] = {
+ "avdd",
+ "dvdd",
+ "pvdd",
+ "a2vdd",
+ "v3p3",
+ "v1p2",
+};
+
+static int adv7511_init_regulators(struct adv7511 *adv)
+{
+ struct device *dev = &adv->i2c_main->dev;
+ const char * const *supply_names;
+ unsigned int i;
+ int ret;
+
+ if (adv->type == ADV7511) {
+ supply_names = adv7511_supply_names;
+ adv->num_supplies = ARRAY_SIZE(adv7511_supply_names);
+ } else {
+ supply_names = adv7533_supply_names;
+ adv->num_supplies = ARRAY_SIZE(adv7533_supply_names);
+ }
+
+ adv->supplies = devm_kcalloc(dev, adv->num_supplies,
+ sizeof(*adv->supplies), GFP_KERNEL);
+ if (!adv->supplies)
+ return -ENOMEM;
+
+ for (i = 0; i < adv->num_supplies; i++)
+ adv->supplies[i].supply = supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, adv->num_supplies, adv->supplies);
+ if (ret)
+ return ret;
+
+ return regulator_bulk_enable(adv->num_supplies, adv->supplies);
+}
+
+static void adv7511_uninit_regulators(struct adv7511 *adv)
+{
+ regulator_bulk_disable(adv->num_supplies, adv->supplies);
+}
+
static int adv7511_parse_dt(struct device_node *np,
struct adv7511_link_config *config)
{
@@ -939,6 +1020,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (!adv7511)
return -ENOMEM;
+ adv7511->i2c_main = i2c;
adv7511->powered = false;
adv7511->status = connector_status_disconnected;
@@ -956,13 +1038,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (ret)
return ret;
+ ret = adv7511_init_regulators(adv7511);
+ if (ret) {
+ dev_err(dev, "failed to init regulators\n");
+ return ret;
+ }
+
/*
* The power down GPIO is optional. If present, toggle it from active to
* inactive to wake up the encoder.
*/
adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
- if (IS_ERR(adv7511->gpio_pd))
- return PTR_ERR(adv7511->gpio_pd);
+ if (IS_ERR(adv7511->gpio_pd)) {
+ ret = PTR_ERR(adv7511->gpio_pd);
+ goto uninit_regulators;
+ }
if (adv7511->gpio_pd) {
mdelay(5);
@@ -970,12 +1060,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
}
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
- if (IS_ERR(adv7511->regmap))
- return PTR_ERR(adv7511->regmap);
+ if (IS_ERR(adv7511->regmap)) {
+ ret = PTR_ERR(adv7511->regmap);
+ goto uninit_regulators;
+ }
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
if (ret)
- return ret;
+ goto uninit_regulators;
dev_dbg(dev, "Rev. %d\n", val);
if (adv7511->type == ADV7511)
@@ -985,7 +1077,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
else
ret = adv7533_patch_registers(adv7511);
if (ret)
- return ret;
+ goto uninit_regulators;
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
@@ -995,10 +1087,11 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
adv7511_packet_disable(adv7511, 0xffff);
- adv7511->i2c_main = i2c;
adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
- if (!adv7511->i2c_edid)
- return -ENOMEM;
+ if (!adv7511->i2c_edid) {
+ ret = -ENOMEM;
+ goto uninit_regulators;
+ }
if (adv7511->type == ADV7533) {
ret = adv7533_init_cec(adv7511);
@@ -1006,6 +1099,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
goto err_i2c_unregister_edid;
}
+ INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
+
if (i2c->irq) {
init_waitqueue_head(&adv7511->wq);
@@ -1045,6 +1140,8 @@ err_unregister_cec:
adv7533_uninit_cec(adv7511);
err_i2c_unregister_edid:
i2c_unregister_device(adv7511->i2c_edid);
+uninit_regulators:
+ adv7511_uninit_regulators(adv7511);
return ret;
}
@@ -1058,6 +1155,8 @@ static int adv7511_remove(struct i2c_client *i2c)
adv7533_uninit_cec(adv7511);
}
+ adv7511_uninit_regulators(adv7511);
+
drm_bridge_remove(&adv7511->bridge);
adv7511_audio_exit(adv7511);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 02b97bf64ee4..e7cd1056ff2d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1385,6 +1385,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
phy_power_on(dp->phy);
analogix_dp_init_dp(dp);
@@ -1417,9 +1418,15 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
goto err_disable_pm_runtime;
}
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
+
return 0;
err_disable_pm_runtime:
+
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f5009ae39b89..9a9ec27d9e28 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -113,13 +113,20 @@ struct dw_hdmi_i2c {
bool is_regaddr;
};
+struct dw_hdmi_phy_data {
+ enum dw_hdmi_phy_type type;
+ const char *name;
+ bool has_svsret;
+};
+
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder *encoder;
- struct drm_bridge *bridge;
+ struct drm_bridge bridge;
- struct platform_device *audio;
enum dw_hdmi_devtype dev_type;
+ unsigned int version;
+
+ struct platform_device *audio;
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -133,7 +140,9 @@ struct dw_hdmi {
u8 edid[HDMI_EDID_LEN];
bool cable_plugin;
+ const struct dw_hdmi_phy_data *phy;
bool phy_enabled;
+
struct drm_display_mode previous_mode;
struct i2c_adapter *ddc;
@@ -868,7 +877,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -882,13 +891,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
- unsigned char addr)
-{
- __hdmi_phy_i2c_write(hdmi, data, addr);
- return 0;
-}
-
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
@@ -903,11 +905,11 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_SPARECTRL_OFFSET,
- HDMI_PHY_CONF0_SPARECTRL_MASK);
+ HDMI_PHY_CONF0_SVSRET_OFFSET,
+ HDMI_PHY_CONF0_SVSRET_MASK);
}
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
@@ -938,34 +940,14 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
- unsigned char res, int cscon)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
{
- unsigned res_idx;
u8 val, msec;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
- if (prep)
- return -EINVAL;
-
- switch (res) {
- case 0: /* color resolution 0 is 8 bit colour depth */
- case 8:
- res_idx = DW_HDMI_RES_8;
- break;
- case 10:
- res_idx = DW_HDMI_RES_10;
- break;
- case 12:
- res_idx = DW_HDMI_RES_12;
- break;
- default:
- return -EINVAL;
- }
-
/* PLL/MPLL Cfg - always match on final entry */
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
@@ -1004,9 +986,13 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
/* gen2 pddq */
dw_hdmi_phy_gen2_pddq(hdmi, 1);
- /* PHY reset */
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+ /* Leave low power consumption mode by asserting SVSRET. */
+ if (hdmi->phy->has_svsret)
+ dw_hdmi_phy_enable_svsret(hdmi, 1);
+
+ /* PHY reset. The reset signal is active high on Gen2 PHYs. */
+ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+ hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
@@ -1015,21 +1001,26 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
-
- /* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
+ HDMI_3D_TX_PHY_CPCE_CTRL);
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
+ HDMI_3D_TX_PHY_GMPCTRL);
+ hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
+ HDMI_3D_TX_PHY_CURRCTRL);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
- hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
+ hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
+ HDMI_3D_TX_PHY_MSM_CTRL);
- hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19); /* TXTERM */
- hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
- hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
+ hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
+ hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+ HDMI_3D_TX_PHY_CKSYMTXCTRL);
+ hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+ HDMI_3D_TX_PHY_VLEVCTRL);
- /* REMOVE CLK TERM */
- hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
+ /* Override and disable clock termination. */
+ hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
+ HDMI_3D_TX_PHY_CKCALCTRL);
dw_hdmi_phy_enable_powerdown(hdmi, false);
@@ -1041,10 +1032,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
- if (hdmi->dev_type == RK3288_HDMI)
- dw_hdmi_phy_enable_spare(hdmi, 1);
-
- /*Wait for PHY PLL lock */
+ /* Wait for PHY PLL lock */
msec = 5;
do {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
@@ -1079,7 +1067,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */
- ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+ ret = hdmi_phy_configure(hdmi, cscon);
if (ret)
return ret;
}
@@ -1351,19 +1339,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
/* Workaround to clear the overflow condition */
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
- int count;
+ unsigned int count;
+ unsigned int i;
u8 val;
- /* TMDS software reset */
- hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+ /*
+ * Under some circumstances the Frame Composer arithmetic unit can miss
+ * an FC register write due to being busy processing the previous one.
+ * The issue can be worked around by issuing a TMDS software reset and
+ * then write one of the FC registers several times.
+ *
+ * The number of iterations matters and depends on the HDMI TX revision
+ * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
+ * i.MX6DL (v1.31a) have been identified as needing the workaround, with
+ * 4 and 1 iterations respectively.
+ */
- val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
- if (hdmi->dev_type == IMX6DL_HDMI) {
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+ switch (hdmi->version) {
+ case 0x130a:
+ count = 4;
+ break;
+ case 0x131a:
+ count = 1;
+ break;
+ default:
return;
}
- for (count = 0; count < 4; count++)
+ /* TMDS software reset */
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+ val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+ for (i = 0; i < count; i++)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
@@ -1586,42 +1593,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
}
-static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
- struct drm_display_mode *orig_mode,
- struct drm_display_mode *mode)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-
- mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
- hdmi->disabled = true;
- dw_hdmi_update_power(hdmi);
- dw_hdmi_update_phy_mask(hdmi);
- mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
- hdmi->disabled = false;
- dw_hdmi_update_power(hdmi);
- dw_hdmi_update_phy_mask(hdmi);
- mutex_unlock(&hdmi->mutex);
-}
-
static enum drm_connector_status
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
@@ -1714,7 +1685,63 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
.best_encoder = drm_atomic_helper_best_encoder,
};
+static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_connector *connector = &hdmi->connector;
+
+ connector->interlace_allowed = 1;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
+
+ drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ return 0;
+}
+
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+
+ mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = true;
+ dw_hdmi_update_power(hdmi);
+ dw_hdmi_update_phy_mask(hdmi);
+ mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = false;
+ dw_hdmi_update_power(hdmi);
+ dw_hdmi_update_phy_mask(hdmi);
+ mutex_unlock(&hdmi->mutex);
+}
+
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .attach = dw_hdmi_bridge_attach,
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
.mode_set = dw_hdmi_bridge_mode_set,
@@ -1816,7 +1843,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
- drm_helper_hpd_irq_event(hdmi->bridge->dev);
+ if (hdmi->bridge.dev)
+ drm_helper_hpd_irq_event(hdmi->bridge.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
@@ -1826,67 +1854,80 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
-{
- struct drm_encoder *encoder = hdmi->encoder;
- struct drm_bridge *bridge;
- int ret;
-
- bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
- if (!bridge) {
- DRM_ERROR("Failed to allocate drm bridge\n");
- return -ENOMEM;
- }
-
- hdmi->bridge = bridge;
- bridge->driver_private = hdmi;
- bridge->funcs = &dw_hdmi_bridge_funcs;
- ret = drm_bridge_attach(encoder, bridge, NULL);
- if (ret) {
- DRM_ERROR("Failed to initialize bridge with drm\n");
- return -EINVAL;
+static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {
+ {
+ .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
+ .name = "DWC HDMI TX PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
+ .name = "DWC MHL PHY + HEAC PHY",
+ .has_svsret = true,
+ }, {
+ .type = DW_HDMI_PHY_DWC_MHL_PHY,
+ .name = "DWC MHL PHY",
+ .has_svsret = true,
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
+ .name = "DWC HDMI 3D TX PHY + HEAC PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
+ .name = "DWC HDMI 3D TX PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
+ .name = "DWC HDMI 2.0 TX PHY",
+ .has_svsret = true,
}
+};
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
+{
+ unsigned int i;
+ u8 phy_type;
- drm_connector_helper_add(&hdmi->connector,
- &dw_hdmi_connector_helper_funcs);
+ phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
- drm_connector_init(drm, &hdmi->connector,
- &dw_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
+ for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
+ if (dw_hdmi_phys[i].type == phy_type) {
+ hdmi->phy = &dw_hdmi_phys[i];
+ return 0;
+ }
+ }
- drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+ if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
+ dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
+ else
+ dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
+ phy_type);
- return 0;
+ return -ENODEV;
}
-int dw_hdmi_bind(struct device *dev, struct device *master,
- void *data, struct drm_encoder *encoder,
- struct resource *iores, int irq,
- const struct dw_hdmi_plat_data *plat_data)
+static struct dw_hdmi *
+__dw_hdmi_probe(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
- struct drm_device *drm = data;
+ struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
struct dw_hdmi *hdmi;
+ struct resource *iores;
+ int irq;
int ret;
u32 val = 1;
+ u8 prod_id0;
+ u8 prod_id1;
u8 config0;
- u8 config1;
+ u8 config3;
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
- return -ENOMEM;
-
- hdmi->connector.interlace_allowed = 1;
+ return ERR_PTR(-ENOMEM);
hdmi->plat_data = plat_data;
hdmi->dev = dev;
hdmi->dev_type = plat_data->dev_type;
hdmi->sample_rate = 48000;
- hdmi->encoder = encoder;
hdmi->disabled = true;
hdmi->rxsense = true;
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
@@ -1908,7 +1949,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
break;
default:
dev_err(dev, "reg-io-width must be 1 or 4\n");
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
@@ -1917,13 +1958,14 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
of_node_put(ddc_node);
if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
- return -EPROBE_DEFER;
+ return ERR_PTR(-EPROBE_DEFER);
}
} else {
dev_dbg(hdmi->dev, "no ddc property found\n");
}
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs)) {
ret = PTR_ERR(hdmi->regs);
@@ -1957,15 +1999,36 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
}
/* Product and revision IDs */
- dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
+ | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
+ prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
+ prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
+
+ if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX ||
+ (prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) {
+ dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n",
+ hdmi->version, prod_id0, prod_id1);
+ ret = -ENODEV;
+ goto err_iahb;
+ }
+
+ ret = dw_hdmi_detect_phy(hdmi);
+ if (ret < 0)
+ goto err_iahb;
+
+ dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
+ hdmi->version >> 12, hdmi->version & 0xfff,
+ prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
+ hdmi->phy->name);
initialize_hdmi_ih_mutes(hdmi);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto err_iahb;
+ }
+
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
@@ -1995,11 +2058,13 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
HDMI_IH_PHY_STAT0);
- ret = dw_hdmi_fb_registered(hdmi);
- if (ret)
- goto err_iahb;
+ hdmi->bridge.driver_private = hdmi;
+ hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
+#ifdef CONFIG_OF
+ hdmi->bridge.of_node = pdev->dev.of_node;
+#endif
- ret = dw_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
goto err_iahb;
@@ -2012,9 +2077,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
pdevinfo.id = PLATFORM_DEVID_AUTO;
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
- config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
- if (config1 & HDMI_CONFIG1_AHB) {
+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
struct dw_hdmi_audio_data audio;
audio.phys = iores->start;
@@ -2046,9 +2111,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
if (hdmi->i2c)
dw_hdmi_i2c_init(hdmi);
- dev_set_drvdata(dev, hdmi);
+ platform_set_drvdata(pdev, hdmi);
- return 0;
+ return hdmi;
err_iahb:
if (hdmi->i2c) {
@@ -2062,14 +2127,11 @@ err_isfr:
err_res:
i2c_put_adapter(hdmi->ddc);
- return ret;
+ return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
+static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
{
- struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
if (hdmi->audio && !IS_ERR(hdmi->audio))
platform_device_unregister(hdmi->audio);
@@ -2084,6 +2146,70 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
else
i2c_put_adapter(hdmi->ddc);
}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int dw_hdmi_probe(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
+{
+ struct dw_hdmi *hdmi;
+ int ret;
+
+ hdmi = __dw_hdmi_probe(pdev, plat_data);
+ if (IS_ERR(hdmi))
+ return PTR_ERR(hdmi);
+
+ ret = drm_bridge_add(&hdmi->bridge);
+ if (ret < 0) {
+ __dw_hdmi_remove(hdmi);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_probe);
+
+void dw_hdmi_remove(struct platform_device *pdev)
+{
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&hdmi->bridge);
+
+ __dw_hdmi_remove(hdmi);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
+{
+ struct dw_hdmi *hdmi;
+ int ret;
+
+ hdmi = __dw_hdmi_probe(pdev, plat_data);
+ if (IS_ERR(hdmi))
+ return PTR_ERR(hdmi);
+
+ ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
+ if (ret) {
+ dw_hdmi_remove(pdev);
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
+
+void dw_hdmi_unbind(struct device *dev)
+{
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+ __dw_hdmi_remove(hdmi);
+}
EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index 55135bbd0c16..325b0b8ae639 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,12 +545,24 @@
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
enum {
+/* PRODUCT_ID0 field values */
+ HDMI_PRODUCT_ID0_HDMI_TX = 0xa0,
+
+/* PRODUCT_ID1 field values */
+ HDMI_PRODUCT_ID1_HDCP = 0xc0,
+ HDMI_PRODUCT_ID1_HDMI_RX = 0x02,
+ HDMI_PRODUCT_ID1_HDMI_TX = 0x01,
+
/* CONFIG0_ID field values */
HDMI_CONFIG0_I2S = 0x10,
/* CONFIG1_ID field values */
HDMI_CONFIG1_AHB = 0x01,
+/* CONFIG3_ID field values */
+ HDMI_CONFIG3_AHBAUDDMA = 0x02,
+ HDMI_CONFIG3_GPAUD = 0x01,
+
/* IH_FC_INT2 field values */
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
@@ -847,8 +859,8 @@ enum {
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
- HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
- HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
+ HDMI_PHY_CONF0_SVSRET_MASK = 0x20,
+ HDMI_PHY_CONF0_SVSRET_OFFSET = 5,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
@@ -977,8 +989,7 @@ enum {
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
/* MC_PHYRSTZ field values */
- HDMI_MC_PHYRSTZ_ASSERT = 0x0,
- HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+ HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01,
/* MC_HEACPHY_RST field values */
HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
@@ -1073,4 +1084,70 @@ enum {
HDMI_I2CM_CTLINT_ARB_MASK = 0x4,
};
+/*
+ * HDMI 3D TX PHY registers
+ */
+#define HDMI_3D_TX_PHY_PWRCTRL 0x00
+#define HDMI_3D_TX_PHY_SERDIVCTRL 0x01
+#define HDMI_3D_TX_PHY_SERCKCTRL 0x02
+#define HDMI_3D_TX_PHY_SERCKKILLCTRL 0x03
+#define HDMI_3D_TX_PHY_TXRESCTRL 0x04
+#define HDMI_3D_TX_PHY_CKCALCTRL 0x05
+#define HDMI_3D_TX_PHY_CPCE_CTRL 0x06
+#define HDMI_3D_TX_PHY_TXCLKMEASCTRL 0x07
+#define HDMI_3D_TX_PHY_TXMEASCTRL 0x08
+#define HDMI_3D_TX_PHY_CKSYMTXCTRL 0x09
+#define HDMI_3D_TX_PHY_CMPSEQCTRL 0x0a
+#define HDMI_3D_TX_PHY_CMPPWRCTRL 0x0b
+#define HDMI_3D_TX_PHY_CMPMODECTRL 0x0c
+#define HDMI_3D_TX_PHY_MEASCTRL 0x0d
+#define HDMI_3D_TX_PHY_VLEVCTRL 0x0e
+#define HDMI_3D_TX_PHY_D2ACTRL 0x0f
+#define HDMI_3D_TX_PHY_CURRCTRL 0x10
+#define HDMI_3D_TX_PHY_DRVANACTRL 0x11
+#define HDMI_3D_TX_PHY_PLLMEASCTRL 0x12
+#define HDMI_3D_TX_PHY_PLLPHBYCTRL 0x13
+#define HDMI_3D_TX_PHY_GRP_CTRL 0x14
+#define HDMI_3D_TX_PHY_GMPCTRL 0x15
+#define HDMI_3D_TX_PHY_MPLLMEASCTRL 0x16
+#define HDMI_3D_TX_PHY_MSM_CTRL 0x17
+#define HDMI_3D_TX_PHY_SCRPB_STATUS 0x18
+#define HDMI_3D_TX_PHY_TXTERM 0x19
+#define HDMI_3D_TX_PHY_PTRPT_ENBL 0x1a
+#define HDMI_3D_TX_PHY_PATTERNGEN 0x1b
+#define HDMI_3D_TX_PHY_SDCAP_MODE 0x1c
+#define HDMI_3D_TX_PHY_SCOPEMODE 0x1d
+#define HDMI_3D_TX_PHY_DIGTXMODE 0x1e
+#define HDMI_3D_TX_PHY_STR_STATUS 0x1f
+#define HDMI_3D_TX_PHY_SCOPECNT0 0x20
+#define HDMI_3D_TX_PHY_SCOPECNT1 0x21
+#define HDMI_3D_TX_PHY_SCOPECNT2 0x22
+#define HDMI_3D_TX_PHY_SCOPECNTCLK 0x23
+#define HDMI_3D_TX_PHY_SCOPESAMPLE 0x24
+#define HDMI_3D_TX_PHY_SCOPECNTMSB01 0x25
+#define HDMI_3D_TX_PHY_SCOPECNTMSB2CK 0x26
+
+/* HDMI_3D_TX_PHY_CKCALCTRL values */
+#define HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE BIT(15)
+
+/* HDMI_3D_TX_PHY_MSM_CTRL values */
+#define HDMI_3D_TX_PHY_MSM_CTRL_MPLL_PH_SEL_CK BIT(13)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_CLK_REF_MPLL (0 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_OFF (1 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_PCLK (2 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK (3 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_SCOPE_CK_SEL BIT(0)
+
+/* HDMI_3D_TX_PHY_PTRPT_ENBL values */
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_OVERRIDE BIT(15)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT2 BIT(8)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT1 BIT(7)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT0 BIT(6)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CK_REF_ENB BIT(5)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_RCAL_ENB BIT(4)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_CLK_ALIGN_ENB BIT(3)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_READY BIT(2)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CKO_WORD_ENB BIT(1)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_REFCLK_ENB BIT(0)
+
#endif /* __DW_HDMI_H__ */
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig
index ca3809851377..fc78c90ee931 100644
--- a/drivers/gpu/drm/cirrus/Kconfig
+++ b/drivers/gpu/drm/cirrus/Kconfig
@@ -7,3 +7,12 @@ config DRM_CIRRUS_QEMU
This is a KMS driver for emulated cirrus device in qemu.
It is *NOT* intended for real cirrus devices. This requires
the modesetting userspace X.org driver.
+
+ Cirrus is obsolete, the hardware was designed in the 90ies
+ and can't keep up with todays needs. More background:
+ https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
+
+ Better alternatives are:
+ - stdvga (DRM_BOCHS, qemu -vga std, default in qemu 2.2+)
+ - qxl (DRM_QXL, qemu -vga qxl, works best with spice)
+ - virtio (DRM_VIRTIO_GPU), qemu -vga virtio)
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index d6da848f7c6f..f53aa8f4a143 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -236,8 +236,6 @@ struct ttm_bo_driver cirrus_bo_driver = {
.verify_access = cirrus_bo_verify_access,
.io_mem_reserve = &cirrus_ttm_io_mem_reserve,
.io_mem_free = &cirrus_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int cirrus_mm_init(struct cirrus_device *cirrus)
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c
index d621c8a4cf00..c89953449e96 100644
--- a/drivers/gpu/drm/drm_agpsupport.c
+++ b/drivers/gpu/drm/drm_agpsupport.c
@@ -421,6 +421,8 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
head->base = head->agp_info.aper_base;
return head;
}
+/* Only exported for i810.ko */
+EXPORT_SYMBOL(drm_agp_init);
/**
* drm_legacy_agp_clear - Clear AGP resource list
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6414bcf7f41b..e5b738660d66 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -195,8 +195,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_clear);
* all locks. So someone else could sneak in and change the current modeset
* configuration. Which means that all the state assembled in @state is no
* longer an atomic update to the current state, but to some arbitrary earlier
- * state. Which could break assumptions the driver's ->atomic_check likely
- * relies on.
+ * state. Which could break assumptions the driver's
+ * &drm_mode_config_funcs.atomic_check likely relies on.
*
* Hence we must clear all cached state and completely start over, using this
* function.
@@ -456,11 +456,10 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
* @property: the property to set
* @val: the new property value
*
- * Use this instead of calling crtc->atomic_set_property directly.
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_set_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_crtc_funcs.atomic_set_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -532,10 +531,10 @@ EXPORT_SYMBOL(drm_atomic_crtc_set_property);
* @property: the property to set
* @val: return location for the property value
*
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_get_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_crtc_funcs.atomic_get_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -716,11 +715,10 @@ EXPORT_SYMBOL(drm_atomic_get_plane_state);
* @property: the property to set
* @val: the new property value
*
- * Use this instead of calling plane->atomic_set_property directly.
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_set_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_plane_funcs.atomic_set_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -791,10 +789,10 @@ EXPORT_SYMBOL(drm_atomic_plane_set_property);
* @property: the property to set
* @val: return location for the property value
*
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_get_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_plane_funcs.atomic_get_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -1057,11 +1055,10 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
* @property: the property to set
* @val: the new property value
*
- * Use this instead of calling connector->atomic_set_property directly.
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_set_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_connector_funcs.atomic_set_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -1136,10 +1133,10 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
* @property: the property to set
* @val: return location for the property value
*
- * This function handles generic/core properties and calls out to
- * driver's ->atomic_get_property() for driver properties. To ensure
- * consistent behavior you must call this function rather than the
- * driver hook directly.
+ * This function handles generic/core properties and calls out to driver's
+ * &drm_connector_funcs.atomic_get_property for driver properties. To ensure
+ * consistent behavior you must call this function rather than the driver hook
+ * directly.
*
* RETURNS:
* Zero on success, error code on failure
@@ -1312,12 +1309,11 @@ EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
* implicit or explicit fencing.
*
* This function will not set the fence to the state if it was set
- * via explicit fencing interfaces on the atomic ioctl. It will
- * all drope the reference to the fence as we not storing it
- * anywhere.
- *
- * Otherwise, if plane_state->fence is not set this function we
- * just set it with the received implict fence.
+ * via explicit fencing interfaces on the atomic ioctl. In that case it will
+ * drop the reference to the fence as we are not storing it anywhere.
+ * Otherwise, if &drm_plane_state.fence is not set this function we just set it
+ * with the received implicit fence. In both cases this function consumes a
+ * reference for @fence.
*/
void
drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
@@ -1616,7 +1612,7 @@ int drm_atomic_commit(struct drm_atomic_state *state)
EXPORT_SYMBOL(drm_atomic_commit);
/**
- * drm_atomic_nonblocking_commit - atomic&nonblocking configuration commit
+ * drm_atomic_nonblocking_commit - atomic nonblocking commit
* @state: atomic configuration to check
*
* Note that this function can return -EDEADLK if the driver needed to acquire
@@ -1731,13 +1727,6 @@ int drm_atomic_debugfs_init(struct drm_minor *minor)
ARRAY_SIZE(drm_atomic_debugfs_list),
minor->debugfs_root, minor);
}
-
-int drm_atomic_debugfs_cleanup(struct drm_minor *minor)
-{
- return drm_debugfs_remove_files(drm_atomic_debugfs_list,
- ARRAY_SIZE(drm_atomic_debugfs_list),
- minor);
-}
#endif
/*
@@ -1829,10 +1818,10 @@ static int atomic_set_prop(struct drm_atomic_state *state,
* @plane_mask: plane mask for planes that were updated.
* @ret: return value, can be -EDEADLK for a retry.
*
- * Before doing an update plane->old_fb is set to plane->fb,
- * but before dropping the locks old_fb needs to be set to NULL
- * and plane->fb updated. This is a common operation for each
- * atomic update, so this call is split off as a helper.
+ * Before doing an update &drm_plane.old_fb is set to &drm_plane.fb, but before
+ * dropping the locks old_fb needs to be set to NULL and plane->fb updated. This
+ * is a common operation for each atomic update, so this call is split off as a
+ * helper.
*/
void drm_atomic_clean_old_fb(struct drm_device *dev,
unsigned plane_mask,
@@ -1873,7 +1862,7 @@ EXPORT_SYMBOL(drm_atomic_clean_old_fb);
* As a contrast, with implicit fencing the kernel keeps track of any
* ongoing rendering, and automatically ensures that the atomic update waits
* for any pending rendering to complete. For shared buffers represented with
- * a &struct dma_buf this is tracked in &reservation_object structures.
+ * a &struct dma_buf this is tracked in &struct reservation_object.
* Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org),
* whereas explicit fencing is what Android wants.
*
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 9460f3a4c1c2..9a08445a7a7a 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -458,22 +458,25 @@ mode_fixup(struct drm_atomic_state *state)
* Check the state object to see if the requested state is physically possible.
* This does all the crtc and connector related computations for an atomic
* update and adds any additional connectors needed for full modesets and calls
- * down into ->mode_fixup functions of the driver backend.
- *
- * crtc_state->mode_changed is set when the input mode is changed.
- * crtc_state->connectors_changed is set when a connector is added or
- * removed from the crtc.
- * crtc_state->active_changed is set when crtc_state->active changes,
- * which is used for dpms.
+ * down into &drm_crtc_helper_funcs.mode_fixup and
+ * &drm_encoder_helper_funcs.mode_fixup or
+ * &drm_encoder_helper_funcs.atomic_check functions of the driver backend.
+ *
+ * &drm_crtc_state.mode_changed is set when the input mode is changed.
+ * &drm_crtc_state.connectors_changed is set when a connector is added or
+ * removed from the crtc. &drm_crtc_state.active_changed is set when
+ * &drm_crtc_state.active changes, which is used for DPMS.
* See also: drm_atomic_crtc_needs_modeset()
*
* IMPORTANT:
*
- * Drivers which set ->mode_changed (e.g. in their ->atomic_check hooks if a
- * plane update can't be done without a full modeset) _must_ call this function
- * afterwards after that change. It is permitted to call this function multiple
- * times for the same update, e.g. when the ->atomic_check functions depend upon
- * the adjusted dotclock for fifo space allocation and watermark computation.
+ * Drivers which set &drm_crtc_state.mode_changed (e.g. in their
+ * &drm_plane_helper_funcs.atomic_check hooks if a plane update can't be done
+ * without a full modeset) _must_ call this function afterwards after that
+ * change. It is permitted to call this function multiple times for the same
+ * update, e.g. when the &drm_crtc_helper_funcs.atomic_check functions depend
+ * upon the adjusted dotclock for fifo space allocation and watermark
+ * computation.
*
* RETURNS:
* Zero for success or -errno
@@ -584,9 +587,10 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
*
* Check the state object to see if the requested state is physically possible.
* This does all the plane update related checks using by calling into the
- * ->atomic_check hooks provided by the driver.
+ * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check
+ * hooks provided by the driver.
*
- * It also sets crtc_state->planes_changed to indicate that a crtc has
+ * It also sets &drm_crtc_state.planes_changed to indicate that a crtc has
* updated planes.
*
* RETURNS:
@@ -648,14 +652,15 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes);
* Check the state object to see if the requested state is physically possible.
* Only crtcs and planes have check callbacks, so for any additional (global)
* checking that a driver needs it can simply wrap that around this function.
- * Drivers without such needs can directly use this as their ->atomic_check()
- * callback.
+ * Drivers without such needs can directly use this as their
+ * &drm_mode_config_funcs.atomic_check callback.
*
* This just wraps the two parts of the state checking for planes and modeset
* state in the default order: First it calls drm_atomic_helper_check_modeset()
* and then drm_atomic_helper_check_planes(). The assumption is that the
- * ->atomic_check functions depend upon an updated adjusted_mode.clock to
- * e.g. properly compute watermarks.
+ * @drm_plane_helper_funcs.atomic_check and @drm_crtc_helper_funcs.atomic_check
+ * functions depend upon an updated adjusted_mode.clock to e.g. properly compute
+ * watermarks.
*
* RETURNS:
* Zero for success or -errno
@@ -1125,8 +1130,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
* drm_atomic_helper_commit_tail - commit atomic update to hardware
* @old_state: atomic state object with old state structures
*
- * This is the default implemenation for the ->atomic_commit_tail() hook of the
- * &drm_mode_config_helper_funcs vtable.
+ * This is the default implementation for the
+ * &drm_mode_config_helper_funcs.atomic_commit_tail hook.
*
* Note that the default ordering of how the various stages are called is to
* match the legacy modeset helper library closest. One peculiarity of that is
@@ -1203,8 +1208,8 @@ static void commit_work(struct work_struct *work)
* drm_atomic_helper_setup_commit() and related functions.
*
* Committing the actual hardware state is done through the
- * ->atomic_commit_tail() callback of the &drm_mode_config_helper_funcs vtable,
- * or it's default implementation drm_atomic_helper_commit_tail().
+ * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or it's default
+ * implementation drm_atomic_helper_commit_tail().
*
* RETURNS:
* Zero for success or -errno.
@@ -1227,8 +1232,10 @@ int drm_atomic_helper_commit(struct drm_device *dev,
if (!nonblock) {
ret = drm_atomic_helper_wait_for_fences(dev, state, true);
- if (ret)
+ if (ret) {
+ drm_atomic_helper_cleanup_planes(dev, state);
return ret;
+ }
}
/*
@@ -1355,7 +1362,7 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock)
return ret < 0 ? ret : 0;
}
-void release_crtc_commit(struct completion *completion)
+static void release_crtc_commit(struct completion *completion)
{
struct drm_crtc_commit *commit = container_of(completion,
typeof(*commit),
@@ -1371,14 +1378,15 @@ void release_crtc_commit(struct completion *completion)
*
* This function prepares @state to be used by the atomic helper's support for
* nonblocking commits. Drivers using the nonblocking commit infrastructure
- * should always call this function from their ->atomic_commit hook.
+ * should always call this function from their
+ * &drm_mode_config_funcs.atomic_commit hook.
*
* To be able to use this support drivers need to use a few more helper
* functions. drm_atomic_helper_wait_for_dependencies() must be called before
* actually committing the hardware state, and for nonblocking commits this call
* must be placed in the async worker. See also drm_atomic_helper_swap_state()
* and it's stall parameter, for when a driver's commit hooks look at the
- * ->state pointers of &struct drm_crtc, &drm_plane or &drm_connector directly.
+ * &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly.
*
* Completion of the hardware commit step must be signalled using
* drm_atomic_helper_commit_hw_done(). After this step the driver is not allowed
@@ -1487,8 +1495,7 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc)
* This function waits for all preceeding commits that touch the same CRTC as
* @old_state to both be committed to the hardware (as signalled by
* drm_atomic_helper_commit_hw_done) and executed by the hardware (as signalled
- * by calling drm_crtc_vblank_send_event on the event member of
- * &drm_crtc_state).
+ * by calling drm_crtc_vblank_send_event() on the &drm_crtc_state.event).
*
* This is part of the atomic helper support for nonblocking commits, see
* drm_atomic_helper_setup_commit() for an overview.
@@ -1625,8 +1632,9 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
* @state: atomic state object with new state structures
*
* This function prepares plane state, specifically framebuffers, for the new
- * configuration. If any failure is encountered this function will call
- * ->cleanup_fb on any already successfully prepared framebuffer.
+ * configuration, by calling &drm_plane_helper_funcs.prepare_fb. If any failure
+ * is encountered this function will call &drm_plane_helper_funcs.cleanup_fb on
+ * any already successfully prepared framebuffer.
*
* Returns:
* 0 on success, negative error code on failure.
@@ -1706,10 +1714,10 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
*
* Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant
* display controllers require to disable a CRTC's planes when the CRTC is
- * disabled. This function would skip the ->atomic_disable call for a plane if
- * the CRTC of the old plane state needs a modesetting operation. Of course,
- * the drivers need to disable the planes in their CRTC disable callbacks
- * since no one else would do that.
+ * disabled. This function would skip the &drm_plane_helper_funcs.atomic_disable
+ * call for a plane if the CRTC of the old plane state needs a modesetting
+ * operation. Of course, the drivers need to disable the planes in their CRTC
+ * disable callbacks since no one else would do that.
*
* The drm_atomic_helper_commit() default implementation doesn't set the
* ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers.
@@ -1872,7 +1880,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
* planes.
*
* It is a bug to call this function without having implemented the
- * ->atomic_disable() plane hook.
+ * &drm_plane_helper_funcs.atomic_disable plane hook.
*/
void
drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
@@ -1959,8 +1967,8 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
* contains the old state. Also do any other cleanup required with that state.
*
* @stall must be set when nonblocking commits for this driver directly access
- * the ->state pointer of &drm_plane, &drm_crtc or &drm_connector. With the
- * current atomic helpers this is almost always the case, since the helpers
+ * the &drm_plane.state, &drm_crtc.state or &drm_connector.state pointer. With
+ * the current atomic helpers this is almost always the case, since the helpers
* don't pass the right state structures to the callbacks.
*/
void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
@@ -2361,7 +2369,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
if (ret != 0)
return ret;
- drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+ drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
drm_atomic_set_fb_for_plane(primary_state, set->fb);
primary_state->crtc_x = 0;
@@ -2706,6 +2714,44 @@ backoff:
}
EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
+static int page_flip_common(
+ struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct drm_plane *plane = crtc->primary;
+ struct drm_plane_state *plane_state;
+ struct drm_crtc_state *crtc_state;
+ int ret = 0;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ crtc_state->event = event;
+
+ plane_state = drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
+
+ ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+ if (ret != 0)
+ return ret;
+ drm_atomic_set_fb_for_plane(plane_state, fb);
+
+ /* Make sure we don't accidentally do a full modeset. */
+ state->allow_modeset = false;
+ if (!crtc_state->active) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
+ crtc->base.id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
/**
* drm_atomic_helper_page_flip - execute a legacy page flip
* @crtc: DRM crtc
@@ -2713,7 +2759,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
* @event: optional DRM event to signal upon completion
* @flags: flip flags for non-vblank sync'ed updates
*
- * Provides a default page flip implementation using the atomic driver interface.
+ * Provides a default &drm_crtc_funcs.page_flip implementation
+ * using the atomic driver interface.
*
* Note that for now so called async page flips (i.e. updates which are not
* synchronized to vblank) are not supported, since the atomic interfaces have
@@ -2721,6 +2768,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
*
* Returns:
* Returns 0 on success, negative errno numbers on failure.
+ *
+ * See also:
+ * drm_atomic_helper_page_flip_target()
*/
int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
@@ -2729,8 +2779,6 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
{
struct drm_plane *plane = crtc->primary;
struct drm_atomic_state *state;
- struct drm_plane_state *plane_state;
- struct drm_crtc_state *crtc_state;
int ret = 0;
if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
@@ -2741,35 +2789,86 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
return -ENOMEM;
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+
retry:
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- ret = PTR_ERR(crtc_state);
+ ret = page_flip_common(state, crtc, fb, event);
+ if (ret != 0)
goto fail;
- }
- crtc_state->event = event;
- plane_state = drm_atomic_get_plane_state(state, plane);
- if (IS_ERR(plane_state)) {
- ret = PTR_ERR(plane_state);
- goto fail;
- }
+ ret = drm_atomic_nonblocking_commit(state);
- ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+fail:
+ if (ret == -EDEADLK)
+ goto backoff;
+
+ drm_atomic_state_put(state);
+ return ret;
+
+backoff:
+ drm_atomic_state_clear(state);
+ drm_atomic_legacy_backoff(state);
+
+ /*
+ * Someone might have exchanged the framebuffer while we dropped locks
+ * in the backoff code. We need to fix up the fb refcount tracking the
+ * core does for us.
+ */
+ plane->old_fb = plane->fb;
+
+ goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+
+/**
+ * drm_atomic_helper_page_flip_target - do page flip on target vblank period.
+ * @crtc: DRM crtc
+ * @fb: DRM framebuffer
+ * @event: optional DRM event to signal upon completion
+ * @flags: flip flags for non-vblank sync'ed updates
+ * @target: specifying the target vblank period when the flip to take effect
+ *
+ * Provides a default &drm_crtc_funcs.page_flip_target implementation.
+ * Similar to drm_atomic_helper_page_flip() with extra parameter to specify
+ * target vblank period to flip.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_page_flip_target(
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t flags,
+ uint32_t target)
+{
+ struct drm_plane *plane = crtc->primary;
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ int ret = 0;
+
+ if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+ return -EINVAL;
+
+ state = drm_atomic_state_alloc(plane->dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+
+retry:
+ ret = page_flip_common(state, crtc, fb, event);
if (ret != 0)
goto fail;
- drm_atomic_set_fb_for_plane(plane_state, fb);
- /* Make sure we don't accidentally do a full modeset. */
- state->allow_modeset = false;
- if (!crtc_state->active) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
- crtc->base.id);
+ crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+ if (WARN_ON(!crtc_state)) {
ret = -EINVAL;
goto fail;
}
+ crtc_state->target_vblank = target;
ret = drm_atomic_nonblocking_commit(state);
+
fail:
if (ret == -EDEADLK)
goto backoff;
@@ -2790,7 +2889,7 @@ backoff:
goto retry;
}
-EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
/**
* drm_atomic_helper_connector_dpms() - connector dpms helper implementation
@@ -2799,8 +2898,8 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip);
*
* This is the main helper function provided by the atomic helper framework for
* implementing the legacy DPMS connector interface. It computes the new desired
- * ->active state for the corresponding CRTC (if the connector is enabled) and
- * updates it.
+ * &drm_crtc_state.active state for the corresponding CRTC (if the connector is
+ * enabled) and updates it.
*
* Returns:
* Returns 0 on success, negative errno numbers on failure.
@@ -2872,11 +2971,11 @@ backoff:
EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
/**
- * drm_atomic_helper_best_encoder - Helper for &drm_connector_helper_funcs
- * ->best_encoder callback
+ * drm_atomic_helper_best_encoder - Helper for
+ * &drm_connector_helper_funcs.best_encoder callback
* @connector: Connector control structure
*
- * This is a &drm_connector_helper_funcs ->best_encoder callback helper for
+ * This is a &drm_connector_helper_funcs.best_encoder callback helper for
* connectors that support exactly 1 encoder, statically determined at driver
* init time.
*/
@@ -2910,7 +3009,7 @@ EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
*/
/**
- * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
+ * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
* @crtc: drm CRTC
*
* Resets the atomic state for @crtc by freeing the state pointer (which might
@@ -3017,7 +3116,7 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
/**
- * drm_atomic_helper_plane_reset - default ->reset hook for planes
+ * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
* @plane: drm plane
*
* Resets the atomic state for @plane by freeing the state pointer (which might
@@ -3121,8 +3220,9 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
* @conn_state: connector state to assign
*
* Initializes the newly allocated @conn_state and assigns it to
- * #connector ->state, usually required when initializing the drivers
- * or when called from the ->reset hook.
+ * the &drm_conector->state pointer of @connector, usually required when
+ * initializing the drivers or when called from the &drm_connector_funcs.reset
+ * hook.
*
* This is useful for drivers that subclass the connector state.
*/
@@ -3138,7 +3238,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector,
EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
/**
- * drm_atomic_helper_connector_reset - default ->reset hook for connectors
+ * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
* @connector: drm connector
*
* Resets the atomic state for @connector by freeing the state pointer (which
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 860cfe124c2a..7ff697389d74 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -40,8 +40,8 @@
* least once successfully became the device master (either through the
* SET_MASTER IOCTL, or implicitly through opening the primary device node when
* no one else is the current master that time) there exists one &drm_master.
- * This is noted in the is_master member of &drm_file. All other clients have
- * just a pointer to the &drm_master they are associated with.
+ * This is noted in &drm_file.is_master. All other clients have just a pointer
+ * to the &drm_master they are associated with.
*
* In addition only one &drm_master can be the current master for a &drm_device.
* It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index 1f2412c7ccfd..665aafc6ad68 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -40,9 +40,8 @@
* sub-pixel accuracy, which is scaled up to a pixel-aligned destination
* rectangle in the visible area of a &drm_crtc. The visible area of a CRTC is
* defined by the horizontal and vertical visible pixels (stored in @hdisplay
- * and @vdisplay) of the requested mode (stored in @mode in the
- * &drm_crtc_state). These two rectangles are both stored in the
- * &drm_plane_state.
+ * and @vdisplay) of the requested mode (stored in &drm_crtc_state.mode). These
+ * two rectangles are both stored in the &drm_plane_state.
*
* For the atomic ioctl the following standard (atomic) properties on the plane object
* encode the basic plane composition model:
@@ -215,7 +214,7 @@ EXPORT_SYMBOL(drm_rotation_simplify);
* for it in drm core. Drivers can then attach this property to planes to enable
* support for configurable planes arrangement during blending operation.
* Once mutable zpos property has been enabled, the DRM core will automatically
- * calculate drm_plane_state->normalized_zpos values. Usually min should be set
+ * calculate &drm_plane_state.normalized_zpos values. Usually min should be set
* to 0 and max to maximal number of planes for given crtc - 1.
*
* If zpos of some planes cannot be changed (like fixed background or
@@ -367,8 +366,8 @@ done:
* For every CRTC this function checks new states of all planes assigned to
* it and calculates normalized zpos value for these planes. Planes are compared
* first by their zpos values, then by plane id (if zpos is equal). The plane
- * with lowest zpos value is at the bottom. The plane_state->normalized_zpos is
- * then filled with unique values from 0 to number of active planes in crtc
+ * with lowest zpos value is at the bottom. The &drm_plane_state.normalized_zpos
+ * is then filled with unique values from 0 to number of active planes in crtc
* minus one.
*
* RETURNS
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index a7916e5f8864..c3b9aaccdf42 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -29,7 +29,9 @@
*/
#include <linux/export.h>
-#include <drm/drmP.h>
+#include <linux/highmem.h>
+
+#include <drm/drm_cache.h>
#if defined(CONFIG_X86)
#include <asm/smp.h>
@@ -67,6 +69,14 @@ static void drm_cache_flush_clflush(struct page *pages[],
}
#endif
+/**
+ * drm_clflush_pages - Flush dcache lines of a set of pages.
+ * @pages: List of pages to be flushed.
+ * @num_pages: Number of pages in the array.
+ *
+ * Flush every data cache line entry that points to an address belonging
+ * to a page in the array.
+ */
void
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
{
@@ -101,6 +111,13 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
}
EXPORT_SYMBOL(drm_clflush_pages);
+/**
+ * drm_clflush_sg - Flush dcache lines pointing to a scather-gather.
+ * @st: struct sg_table.
+ *
+ * Flush every data cache line entry that points to an address in the
+ * sg.
+ */
void
drm_clflush_sg(struct sg_table *st)
{
@@ -125,6 +142,14 @@ drm_clflush_sg(struct sg_table *st)
}
EXPORT_SYMBOL(drm_clflush_sg);
+/**
+ * drm_clflush_virt_range - Flush dcache lines of a region
+ * @addr: Initial kernel memory address.
+ * @length: Region size.
+ *
+ * Flush every data cache line entry that points to an address in the
+ * region requested.
+ */
void
drm_clflush_virt_range(void *addr, unsigned long length)
{
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 799edd0d308e..e4d2c8a49076 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -38,18 +38,17 @@
* Hence they are reference-counted using drm_connector_reference() and
* drm_connector_unreference().
*
- * KMS driver must create, initialize, register and attach at a struct
- * &drm_connector for each such sink. The instance is created as other KMS
- * objects and initialized by setting the following fields.
- *
- * The connector is then registered with a call to drm_connector_init() with a
- * pointer to the connector functions and a connector type, and exposed through
- * sysfs with a call to drm_connector_register().
+ * KMS driver must create, initialize, register and attach at a &struct
+ * drm_connector for each such sink. The instance is created as other KMS
+ * objects and initialized by setting the following fields. The connector is
+ * initialized with a call to drm_connector_init() with a pointer to the
+ * &struct drm_connector_funcs and a connector type, and then exposed to
+ * userspace with a call to drm_connector_register().
*
* Connectors must be attached to an encoder to be used. For devices that map
* connectors to encoders 1:1, the connector should be attached at
* initialization time with a call to drm_mode_connector_attach_encoder(). The
- * driver must also set the &struct drm_connector encoder field to point to the
+ * driver must also set the &drm_connector.encoder field to point to the
* attached encoder.
*
* For connectors which are not fixed (like built-in panels) the driver needs to
@@ -497,7 +496,7 @@ static struct lockdep_map connector_list_iter_dep_map = {
* @dev: DRM device
* @iter: connector_list iterator
*
- * Sets @iter up to walk the connector list in &drm_mode_config of @dev. @iter
+ * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter
* must always be cleaned up again by calling drm_connector_list_iter_put().
* Iteration itself happens using drm_connector_list_iter_next() or
* drm_for_each_connector_iter().
@@ -696,8 +695,8 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
* drivers this is only provided for backwards compatibility with existing
* drivers, it remaps to controlling the "ACTIVE" property on the CRTC the
* connector is linked to. Drivers should never set this property directly,
- * it is handled by the DRM core by calling the ->dpms() callback in
- * &drm_connector_funcs. Atomic drivers should implement this hook using
+ * it is handled by the DRM core by calling the &drm_connector_funcs.dpms
+ * callback. Atomic drivers should implement this hook using
* drm_atomic_helper_connector_dpms(). This is the only property standard
* connector property that userspace can change.
* PATH:
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index bd3c8b243447..6915f897bd8e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -47,6 +47,27 @@
#include "drm_internal.h"
/**
+ * DOC: overview
+ *
+ * A CRTC represents the overall display pipeline. It receives pixel data from
+ * &drm_plane and blends them together. The &drm_display_mode is also attached
+ * to the CRTC, specifying display timings. On the output side the data is fed
+ * to one or more &drm_encoder, which are then each connected to one
+ * &drm_connector.
+ *
+ * To create a CRTC, a KMS drivers allocates and zeroes an instances of
+ * &struct drm_crtc (possibly as part of a larger structure) and registers it
+ * with a call to drm_crtc_init_with_planes().
+ *
+ * The CRTC is also the entry point for legacy modeset operations, see
+ * &drm_crtc_funcs.set_config, legacy plane operations, see
+ * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy
+ * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these
+ * features are controlled through &drm_property and
+ * &drm_mode_config_funcs.atomic_check and &drm_mode_config_funcs.atomic_check.
+ */
+
+/**
* drm_crtc_from_index - find the registered CRTC at an index
* @dev: DRM device
* @idx: index of registered CRTC to find for
@@ -415,11 +436,12 @@ int drm_mode_getcrtc(struct drm_device *dev,
}
/**
- * drm_mode_set_config_internal - helper to call ->set_config
+ * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config
* @set: modeset config to set
*
- * This is a little helper to wrap internal calls to the ->set_config driver
- * interface. The only thing it adds is correct refcounting dance.
+ * This is a little helper to wrap internal calls to the
+ * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is
+ * correct refcounting dance.
*
* Returns:
* Zero on success, negative errno on failure.
@@ -460,27 +482,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
EXPORT_SYMBOL(drm_mode_set_config_internal);
/**
- * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
- * @mode: mode to query
- * @hdisplay: hdisplay value to fill in
- * @vdisplay: vdisplay value to fill in
- *
- * The vdisplay value will be doubled if the specified mode is a stereo mode of
- * the appropriate layout.
- */
-void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
- int *hdisplay, int *vdisplay)
-{
- struct drm_display_mode adjusted;
-
- drm_mode_copy(&adjusted, mode);
- drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
- *hdisplay = adjusted.crtc_hdisplay;
- *vdisplay = adjusted.crtc_vdisplay;
-}
-EXPORT_SYMBOL(drm_crtc_get_hv_timing);
-
-/**
* drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
* CRTC viewport
* @crtc: CRTC that framebuffer will be displayed on
@@ -497,7 +498,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
{
int hdisplay, vdisplay;
- drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
+ drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
if (crtc->state &&
drm_rotation_90_or_270(crtc->primary->state->rotation))
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 1e281dd42e4b..44ba0e990d6c 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -53,9 +53,9 @@
* configuration on resume with drm_helper_resume_force_mode().
*
* Note that this helper library doesn't track the current power state of CRTCs
- * and encoders. It can call callbacks like ->dpms() even though the hardware is
- * already in the desired state. This deficiency has been fixed in the atomic
- * helpers.
+ * and encoders. It can call callbacks like &drm_encoder_helper_funcs.dpms even
+ * though the hardware is already in the desired state. This deficiency has been
+ * fixed in the atomic helpers.
*
* The driver callbacks are mostly compatible with the atomic modeset helpers,
* except for the handling of the primary plane: Atomic helpers require that the
@@ -477,12 +477,12 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
* drm_crtc_helper_set_config - set a new config from userspace
* @set: mode set configuration
*
- * The drm_crtc_helper_set_config() helper function implements the set_config
- * callback of &struct drm_crtc_funcs for drivers using the legacy CRTC helpers.
+ * The drm_crtc_helper_set_config() helper function implements the of
+ * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC
+ * helpers.
*
* It first tries to locate the best encoder for each connector by calling the
- * connector ->best_encoder() (&struct drm_connector_helper_funcs) helper
- * operation.
+ * connector @drm_connector_helper_funcs.best_encoder helper operation.
*
* After locating the appropriate encoders, the helper function will call the
* mode_fixup encoder and CRTC helper operations to adjust the requested mode,
@@ -493,8 +493,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
*
* If the adjusted mode is identical to the current mode but changes to the
* frame buffer need to be applied, the drm_crtc_helper_set_config() function
- * will call the CRTC ->mode_set_base() (&struct drm_crtc_helper_funcs) helper
- * operation.
+ * will call the CRTC &drm_crtc_helper_funcs.mode_set_base helper operation.
*
* If the adjusted mode differs from the current mode, or if the
* ->mode_set_base() helper operation is not provided, the helper function
@@ -851,14 +850,15 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
* @connector: affected connector
* @mode: DPMS mode
*
- * The drm_helper_connector_dpms() helper function implements the ->dpms()
- * callback of &struct drm_connector_funcs for drivers using the legacy CRTC helpers.
+ * The drm_helper_connector_dpms() helper function implements the
+ * &drm_connector_funcs.dpms callback for drivers using the legacy CRTC
+ * helpers.
*
* This is the main helper function provided by the CRTC helper framework for
* implementing the DPMS connector attribute. It computes the new desired DPMS
- * state for all encoders and CRTCs in the output mesh and calls the ->dpms()
- * callbacks provided by the driver in &struct drm_crtc_helper_funcs and struct
- * &drm_encoder_helper_funcs appropriately.
+ * state for all encoders and CRTCs in the output mesh and calls the
+ * &drm_crtc_helper_funcs.dpms and &drm_encoder_helper_funcs.dpms callbacks
+ * provided by the driver.
*
* This function is deprecated. New drivers must implement atomic modeset
* support, for which this function is unsuitable. Instead drivers should use
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 724c329186d5..1bdcfd566695 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -177,7 +177,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
#ifdef CONFIG_DEBUG_FS
struct drm_minor;
int drm_atomic_debugfs_init(struct drm_minor *minor);
-int drm_atomic_debugfs_cleanup(struct drm_minor *minor);
#endif
int drm_atomic_get_property(struct drm_mode_object *obj,
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 37fd612d57a6..2290a74a6e46 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -81,7 +81,8 @@ static const struct file_operations drm_debugfs_fops = {
* \return Zero on success, non-zero on failure
*
* Create a given set of debugfs files represented by an array of
- * gdm_debugfs_lists in the given root directory.
+ * &drm_info_list in the given root directory. These files will be removed
+ * automatically on drm_debugfs_cleanup().
*/
int drm_debugfs_create_files(const struct drm_info_list *files, int count,
struct dentry *root, struct drm_minor *minor)
@@ -218,6 +219,19 @@ int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
}
EXPORT_SYMBOL(drm_debugfs_remove_files);
+static void drm_debugfs_remove_all_files(struct drm_minor *minor)
+{
+ struct drm_info_node *node, *tmp;
+
+ mutex_lock(&minor->debugfs_lock);
+ list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) {
+ debugfs_remove(node->dent);
+ list_del(&node->list);
+ kfree(node);
+ }
+ mutex_unlock(&minor->debugfs_lock);
+}
+
/**
* Cleanup the debugfs filesystem resources.
*
@@ -229,7 +243,6 @@ EXPORT_SYMBOL(drm_debugfs_remove_files);
int drm_debugfs_cleanup(struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
- int ret;
if (!minor->debugfs_root)
return 0;
@@ -237,17 +250,9 @@ int drm_debugfs_cleanup(struct drm_minor *minor)
if (dev->driver->debugfs_cleanup)
dev->driver->debugfs_cleanup(minor);
- if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
- ret = drm_atomic_debugfs_cleanup(minor);
- if (ret) {
- DRM_ERROR("DRM: Failed to remove atomic debugfs entries\n");
- return ret;
- }
- }
-
- drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES, minor);
+ drm_debugfs_remove_all_files(minor);
- debugfs_remove(minor->debugfs_root);
+ debugfs_remove_recursive(minor->debugfs_root);
minor->debugfs_root = NULL;
return 0;
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 3e6fe82c6d64..68908c1d5ca1 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -725,7 +725,7 @@ MODULE_PARM_DESC(dp_aux_i2c_speed_khz,
/*
* Transfer a single I2C-over-AUX message and handle various error conditions,
* retrying the transaction as appropriate. It is assumed that the
- * aux->transfer function does not modify anything in the msg other than the
+ * &drm_dp_aux.transfer function does not modify anything in the msg other than the
* reply field.
*
* Returns bytes transferred on success, or a negative error code on failure.
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index aa644487749c..122a1b04bebc 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1086,7 +1086,7 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb,
}
static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
- struct device *dev,
+ struct drm_device *dev,
struct drm_dp_link_addr_reply_port *port_msg)
{
struct drm_dp_mst_port *port;
@@ -1104,7 +1104,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
port->port_num = port_msg->port_number;
port->mgr = mstb->mgr;
port->aux.name = "DPMST";
- port->aux.dev = dev;
+ port->aux.dev = dev->dev;
created = true;
} else {
old_pdt = port->pdt;
@@ -2949,7 +2949,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
* Return 0 for success, or negative error code on failure
*/
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
- struct device *dev, struct drm_dp_aux *aux,
+ struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id)
{
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 72116978ec06..6cbd67f4fbc5 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -221,7 +221,7 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
if (ret) {
DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
- return ret;
+ goto err_debugfs;
}
ret = device_add(minor->kdev);
@@ -309,7 +309,7 @@ void drm_minor_release(struct drm_minor *minor)
* userspace the device instance can be published using drm_dev_register().
*
* There is also deprecated support for initalizing device instances using
- * bus-specific helpers and the ->load() callback. But due to
+ * bus-specific helpers and the &drm_driver.load callback. But due to
* backwards-compatibility needs the device instance have to be published too
* early, which requires unpretty global locking to make safe and is therefore
* only support for existing drivers not yet converted to the new scheme.
@@ -720,9 +720,9 @@ static void remove_compat_control_link(struct drm_device *dev)
* Never call this twice on any device!
*
* NOTE: To ensure backward compatibility with existing drivers method this
- * function calls the ->load() method after registering the device nodes,
- * creating race conditions. Usage of the ->load() methods is therefore
- * deprecated, drivers must perform all initialization before calling
+ * function calls the &drm_driver.load method after registering the device
+ * nodes, creating race conditions. Usage of the &drm_driver.load methods is
+ * therefore deprecated, drivers must perform all initialization before calling
* drm_dev_register().
*
* RETURNS:
diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c
index e5c61cda4ae3..10307cc16d75 100644
--- a/drivers/gpu/drm/drm_dumb_buffers.c
+++ b/drivers/gpu/drm/drm_dumb_buffers.c
@@ -42,8 +42,8 @@
* create dumb buffers suitable for scanout, which can then be used to create
* KMS frame buffers.
*
- * To support dumb objects drivers must implement the dumb_create,
- * dumb_destroy and dumb_map_offset operations from &struct drm_driver. See
+ * To support dumb objects drivers must implement the &drm_driver.dumb_create,
+ * &drm_driver.dumb_destroy and &drm_driver.dumb_map_offset operations. See
* there for further details.
*
* Note that dumb objects may not be used for gpu acceleration, as has been
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 4ff04aa84dd0..baa6ccb3e18b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -3768,6 +3768,25 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
}
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
+/**
+ * drm_default_rgb_quant_range - default RGB quantization range
+ * @mode: display mode
+ *
+ * Determine the default RGB quantization range for the mode,
+ * as specified in CEA-861.
+ *
+ * Return: The default RGB quantization range for the mode
+ */
+enum hdmi_quantization_range
+drm_default_rgb_quant_range(const struct drm_display_mode *mode)
+{
+ /* All CEA modes other than VIC 1 use limited quantization range. */
+ return drm_match_cea_mode(mode) > 1 ?
+ HDMI_QUANTIZATION_RANGE_LIMITED :
+ HDMI_QUANTIZATION_RANGE_FULL;
+}
+EXPORT_SYMBOL(drm_default_rgb_quant_range);
+
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
const u8 *hdmi)
{
@@ -4273,6 +4292,52 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
}
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);
+/**
+ * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe
+ * quantization range information
+ * @frame: HDMI AVI infoframe
+ * @mode: DRM display mode
+ * @rgb_quant_range: RGB quantization range (Q)
+ * @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS)
+ */
+void
+drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
+ const struct drm_display_mode *mode,
+ enum hdmi_quantization_range rgb_quant_range,
+ bool rgb_quant_range_selectable)
+{
+ /*
+ * CEA-861:
+ * "A Source shall not send a non-zero Q value that does not correspond
+ * to the default RGB Quantization Range for the transmitted Picture
+ * unless the Sink indicates support for the Q bit in a Video
+ * Capabilities Data Block."
+ *
+ * HDMI 2.0 recommends sending non-zero Q when it does match the
+ * default RGB quantization range for the mode, even when QS=0.
+ */
+ if (rgb_quant_range_selectable ||
+ rgb_quant_range == drm_default_rgb_quant_range(mode))
+ frame->quantization_range = rgb_quant_range;
+ else
+ frame->quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+
+ /*
+ * CEA-861-F:
+ * "When transmitting any RGB colorimetry, the Source should set the
+ * YQ-field to match the RGB Quantization Range being transmitted
+ * (e.g., when Limited Range RGB, set YQ=0 or when Full Range RGB,
+ * set YQ=1) and the Sink shall ignore the YQ-field."
+ */
+ if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)
+ frame->ycc_quantization_range =
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+ else
+ frame->ycc_quantization_range =
+ HDMI_YCC_QUANTIZATION_RANGE_FULL;
+}
+EXPORT_SYMBOL(drm_hdmi_avi_infoframe_quant_range);
+
static enum hdmi_3d_structure
s3d_structure_from_display_mode(const struct drm_display_mode *mode)
{
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 487cfe3989e8..129450713bb7 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -98,7 +98,7 @@ void drm_encoder_unregister_all(struct drm_device *dev)
*
* Initialises a preallocated encoder. Encoder should be subclassed as part of
* driver encoder objects. At driver unload time drm_encoder_cleanup() should be
- * called from the driver's destroy hook in &drm_encoder_funcs.
+ * called from the driver's &drm_encoder_funcs.destroy hook.
*
* Returns:
* Zero on success, error code on failure.
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
index 4484785cd9ac..cf804389f5ec 100644
--- a/drivers/gpu/drm/drm_encoder_slave.c
+++ b/drivers/gpu/drm/drm_encoder_slave.c
@@ -43,7 +43,7 @@
* &drm_encoder_slave. The @slave_funcs field will be initialized with
* the hooks provided by the slave driver.
*
- * If @info->platform_data is non-NULL it will be used as the initial
+ * If @info.platform_data is non-NULL it will be used as the initial
* slave config.
*
* Returns 0 on success or a negative errno on failure, in particular,
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 20a4011f790d..0ef8b284a4b8 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -473,8 +473,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper,
return 0;
err_cma_destroy:
- drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
- drm_fb_cma_destroy(&fbdev_cma->fb->fb);
+ drm_framebuffer_remove(&fbdev_cma->fb->fb);
err_fb_info_destroy:
drm_fb_helper_release_fbi(helper);
err_gem_free_object:
@@ -574,10 +573,8 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev);
drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
- if (fbdev_cma->fb) {
- drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
- drm_fb_cma_destroy(&fbdev_cma->fb->fb);
- }
+ if (fbdev_cma->fb)
+ drm_framebuffer_remove(&fbdev_cma->fb->fb);
drm_fb_helper_fini(&fbdev_cma->fb_helper);
kfree(fbdev_cma);
@@ -625,3 +622,21 @@ void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, int state)
drm_fb_helper_set_suspend(&fbdev_cma->fb_helper, state);
}
EXPORT_SYMBOL(drm_fbdev_cma_set_suspend);
+
+/**
+ * drm_fbdev_cma_set_suspend_unlocked - wrapper around
+ * drm_fb_helper_set_suspend_unlocked
+ * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
+ * @state: desired state, zero to resume, non-zero to suspend
+ *
+ * Calls drm_fb_helper_set_suspend, which is a wrapper around
+ * fb_set_suspend implemented by fbdev core.
+ */
+void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
+ int state)
+{
+ if (fbdev_cma)
+ drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper,
+ state);
+}
+EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0ab6aaacb7d6..c7fafa175755 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -66,11 +66,11 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* Teardown is done with drm_fb_helper_fini().
*
* At runtime drivers should restore the fbdev console by calling
- * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback.
- * They should also notify the fb helper code from updates to the output
- * configuration by calling drm_fb_helper_hotplug_event(). For easier
+ * drm_fb_helper_restore_fbdev_mode_unlocked() from their &drm_driver.lastclose
+ * callback. They should also notify the fb helper code from updates to the
+ * output configuration by calling drm_fb_helper_hotplug_event(). For easier
* integration with the output polling code in drm_crtc_helper.c the modeset
- * code provides a ->output_poll_changed callback.
+ * code provides a &drm_mode_config_funcs.output_poll_changed callback.
*
* All other functions exported by the fb helper library can be used to
* implement the fbdev driver interface by the driver.
@@ -79,7 +79,7 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* hotplug detection using the fbdev helpers. The drm_fb_helper_prepare()
* helper must be called first to initialize the minimum required to make
* hotplug detection work. Drivers also need to make sure to properly set up
- * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init()
+ * the &drm_mode_config.funcs member. After calling drm_kms_helper_poll_init()
* it is safe to enable interrupts and start processing hotplug events. At the
* same time, drivers should initialize all modeset objects such as CRTCs,
* encoders and connectors. To finish up the fbdev helper initialization, the
@@ -88,9 +88,9 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* should call drm_fb_helper_single_add_all_connectors() followed by
* drm_fb_helper_initial_config().
*
- * If &drm_framebuffer_funcs ->dirty is set, the
+ * If &drm_framebuffer_funcs.dirty is set, the
* drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
- * accumulate changes and schedule &drm_fb_helper ->dirty_work to run right
+ * accumulate changes and schedule &drm_fb_helper.dirty_work to run right
* away. This worker then calls the dirty() function ensuring that it will
* always run in process context since the fb_*() function could be running in
* atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io
@@ -247,7 +247,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
}
/**
- * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
+ * 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)
@@ -296,7 +296,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
}
/**
- * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave
+ * 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)
@@ -445,7 +445,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
* drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
* @fb_helper: fbcon to restore
*
- * This should be called from driver's drm ->lastclose callback
+ * This should be called from driver's drm &drm_driver.lastclose callback
* when implementing an fbcon on top of kms using this helper. This ensures that
* the user isn't greeted with a black screen when e.g. X dies.
*
@@ -585,7 +585,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
}
/**
- * drm_fb_helper_blank - implementation for ->fb_blank
+ * drm_fb_helper_blank - implementation for &fb_ops.fb_blank
* @blank: desired blanking state
* @info: fbdev registered by the helper
*/
@@ -912,7 +912,7 @@ static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
* @info: fb_info struct pointer
* @pagelist: list of dirty mmap framebuffer pages
*
- * This function is used as the &fb_deferred_io ->deferred_io
+ * This function is used as the &fb_deferred_io.deferred_io
* callback function for flushing the fbdev mmap writes.
*/
void drm_fb_helper_deferred_io(struct fb_info *info,
@@ -1103,7 +1103,7 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend);
* due to all the printk activity.
*
* This function can be called multiple times with the same state since
- * &fb_info->state is checked to see if fbdev is running or not before locking.
+ * &fb_info.state is checked to see if fbdev is running or not before locking.
*
* Use drm_fb_helper_set_suspend() if you need to take the lock yourself.
*/
@@ -1181,7 +1181,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
}
/**
- * drm_fb_helper_setcmap - implementation for ->fb_setcmap
+ * drm_fb_helper_setcmap - implementation for &fb_ops.fb_setcmap
* @cmap: cmap to set
* @info: fbdev registered by the helper
*/
@@ -1238,7 +1238,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
EXPORT_SYMBOL(drm_fb_helper_setcmap);
/**
- * drm_fb_helper_check_var - implementation for ->fb_check_var
+ * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
* @var: screeninfo to check
* @info: fbdev registered by the helper
*/
@@ -1338,7 +1338,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
EXPORT_SYMBOL(drm_fb_helper_check_var);
/**
- * drm_fb_helper_set_par - implementation for ->fb_set_par
+ * drm_fb_helper_set_par - implementation for &fb_ops.fb_set_par
* @info: fbdev registered by the helper
*
* This will let fbcon do the mode init and is called at initialization time by
@@ -1422,7 +1422,7 @@ backoff:
}
/**
- * drm_fb_helper_pan_display - implementation for ->fb_pan_display
+ * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display
* @var: updated screen information
* @info: fbdev registered by the helper
*/
@@ -1607,7 +1607,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
* additional constraints need to set up their own limits.
*
* Drivers should call this (or their equivalent setup code) from their
- * ->fb_probe callback.
+ * &drm_fb_helper_funcs.fb_probe callback.
*/
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
uint32_t depth)
@@ -1636,11 +1636,11 @@ EXPORT_SYMBOL(drm_fb_helper_fill_fix);
* @fb_height: desired fb height
*
* Sets up the variable fbdev metainformation from the given fb helper instance
- * and the drm framebuffer allocated in fb_helper->fb.
+ * and the drm framebuffer allocated in &drm_fb_helper.fb.
*
* Drivers should call this (or their equivalent setup code) from their
- * ->fb_probe callback after having allocated the fbdev backing
- * storage framebuffer.
+ * &drm_fb_helper_funcs.fb_probe callback after having allocated the fbdev
+ * backing storage framebuffer.
*/
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height)
@@ -2207,9 +2207,9 @@ out:
* Note that this also registers the fbdev and so allows userspace to call into
* the driver through the fbdev interfaces.
*
- * This function will call down into the ->fb_probe callback to let
- * the driver allocate and initialize the fbdev info structure and the drm
- * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
+ * This function will call down into the &drm_fb_helper_funcs.fb_probe callback
+ * to let the driver allocate and initialize the fbdev info structure and the
+ * drm framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
* drm_fb_helper_fill_fix() are provided as helpers to setup simple default
* values for the fbdev info structure.
*
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index e22645375e60..afdf5b147f39 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -580,7 +580,7 @@ EXPORT_SYMBOL(drm_poll);
* kmalloc and @p must be the first member element.
*
* This is the locked version of drm_event_reserve_init() for callers which
- * already hold dev->event_lock.
+ * already hold &drm_device.event_lock.
*
* RETURNS:
*
@@ -621,7 +621,7 @@ EXPORT_SYMBOL(drm_event_reserve_init_locked);
* If callers embedded @p into a larger structure it must be allocated with
* kmalloc and @p must be the first member element.
*
- * Callers which already hold dev->event_lock should use
+ * Callers which already hold &drm_device.event_lock should use
* drm_event_reserve_init_locked() instead.
*
* RETURNS:
@@ -677,7 +677,7 @@ EXPORT_SYMBOL(drm_event_cancel_free);
*
* This function sends the event @e, initialized with drm_event_reserve_init(),
* to its associated userspace DRM file. Callers must already hold
- * dev->event_lock, see drm_send_event() for the unlocked version.
+ * &drm_device.event_lock, see drm_send_event() for the unlocked version.
*
* Note that the core will take care of unlinking and disarming events when the
* corresponding DRM file is closed. Drivers need not worry about whether the
@@ -717,8 +717,9 @@ EXPORT_SYMBOL(drm_send_event_locked);
* @e: DRM event to deliver
*
* This function sends the event @e, initialized with drm_event_reserve_init(),
- * to its associated userspace DRM file. This function acquires dev->event_lock,
- * see drm_send_event_locked() for callers which already hold this lock.
+ * to its associated userspace DRM file. This function acquires
+ * &drm_device.event_lock, see drm_send_event_locked() for callers which already
+ * hold this lock.
*
* Note that the core will take care of unlinking and disarming events when the
* corresponding DRM file is closed. Drivers need not worry about whether the
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 588ccc3a2218..28a0108a1ab8 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -58,8 +58,8 @@
* fbdev framebuffer when the struct &struct drm_framebuffer is embedded into
* the fbdev helper struct) drivers can manually clean up a framebuffer at
* module unload time with drm_framebuffer_unregister_private(). But doing this
- * is not recommended, and it's better to have a normal free-standing struct
- * &drm_framebuffer.
+ * is not recommended, and it's better to have a normal free-standing &struct
+ * drm_framebuffer.
*/
int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
@@ -470,7 +470,7 @@ int drm_mode_getfb(struct drm_device *dev,
* usb display-link, mipi manual update panels or edp panel self refresh modes.
*
* Modesetting drivers which always update the frontbuffer do not need to
- * implement the corresponding ->dirty framebuffer callback.
+ * implement the corresponding &drm_framebuffer_funcs.dirty callback.
*
* Called by the user via ioctl.
*
@@ -709,10 +709,10 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
* @fb: framebuffer to remove
*
* Cleanup framebuffer. This function is intended to be used from the drivers
- * ->destroy callback. It can also be used to clean up driver private
- * framebuffers embedded into a larger structure.
+ * &drm_framebuffer_funcs.destroy callback. It can also be used to clean up
+ * driver private framebuffers embedded into a larger structure.
*
- * Note that this function does not remove the fb from active usuage - if it is
+ * Note that this function does not remove the fb from active usage - if it is
* still used anywhere, hilarity can ensue since userspace could call getfb on
* the id and get back -EINVAL. Obviously no concern at driver unload time.
*
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 465bacd0a630..bc93de308673 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -316,8 +316,8 @@ EXPORT_SYMBOL(drm_gem_handle_delete);
* @dev: corresponding drm_device
* @handle: the dumb handle to remove
*
- * This implements the ->dumb_destroy kms driver callback for drivers which use
- * gem to manage their backing storage.
+ * This implements the &drm_driver.dumb_destroy kms driver callback for drivers
+ * which use gem to manage their backing storage.
*/
int drm_gem_dumb_destroy(struct drm_file *file,
struct drm_device *dev,
@@ -333,9 +333,9 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
* @obj: object to register
* @handlep: pointer to return the created handle to the caller
*
- * This expects the dev->object_name_lock to be held already and will drop it
- * before returning. Used to avoid races in establishing new handles when
- * importing an object from either an flink name or a dma-buf.
+ * This expects the &drm_device.object_name_lock to be held already and will
+ * drop it before returning. Used to avoid races in establishing new handles
+ * when importing an object from either an flink name or a dma-buf.
*
* Handles must be release again through drm_gem_handle_delete(). This is done
* when userspace closes @file_priv for all attached handles, or through the
@@ -447,8 +447,8 @@ EXPORT_SYMBOL(drm_gem_free_mmap_offset);
* structures.
*
* This routine allocates and attaches a fake offset for @obj, in cases where
- * the virtual size differs from the physical size (ie. obj->size). Otherwise
- * just use drm_gem_create_mmap_offset().
+ * the virtual size differs from the physical size (ie. &drm_gem_object.size).
+ * Otherwise just use drm_gem_create_mmap_offset().
*
* This function is idempotent and handles an already allocated mmap offset
* transparently. Drivers do not need to check for this case.
@@ -787,7 +787,7 @@ EXPORT_SYMBOL(drm_gem_object_release);
* @kref: kref of the object to free
*
* Called after the last reference to the object has been lost.
- * Must be called holding &drm_device->struct_mutex.
+ * Must be called holding &drm_device.struct_mutex.
*
* Frees the object
*/
@@ -813,7 +813,7 @@ EXPORT_SYMBOL(drm_gem_object_free);
* @obj: GEM buffer object
*
* This releases a reference to @obj. Callers must not hold the
- * dev->struct_mutex lock when calling this function.
+ * &drm_device.struct_mutex lock when calling this function.
*
* See also __drm_gem_object_unreference().
*/
@@ -840,9 +840,9 @@ EXPORT_SYMBOL(drm_gem_object_unreference_unlocked);
* drm_gem_object_unreference - release a GEM BO reference
* @obj: GEM buffer object
*
- * This releases a reference to @obj. Callers must hold the dev->struct_mutex
- * lock when calling this function, even when the driver doesn't use
- * dev->struct_mutex for anything.
+ * This releases a reference to @obj. Callers must hold the
+ * &drm_device.struct_mutex lock when calling this function, even when the
+ * driver doesn't use &drm_device.struct_mutex for anything.
*
* For drivers not encumbered with legacy locking use
* drm_gem_object_unreference_unlocked() instead.
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index a6213f814345..f37388cb2fde 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -31,6 +31,7 @@ void drm_lastclose(struct drm_device *dev);
/* drm_pci.c */
int drm_irq_by_busid(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void drm_pci_agp_destroy(struct drm_device *dev);
/* drm_prime.c */
int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 88c69e71102e..e06cf11ebb4a 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -95,7 +95,7 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
*
* Only to be called from drm_crtc_vblank_on().
*
- * Note: caller must hold dev->vbl_lock since this reads & writes
+ * Note: caller must hold &drm_device.vbl_lock since this reads & writes
* device vblank fields.
*/
static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe)
@@ -142,7 +142,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
* Only necessary when going from off->on, to account for frames we
* didn't get an interrupt for.
*
- * Note: caller must hold dev->vbl_lock since this reads & writes
+ * Note: caller must hold &drm_device.vbl_lock since this reads & writes
* device vblank fields.
*/
static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
@@ -415,29 +415,6 @@ err:
}
EXPORT_SYMBOL(drm_vblank_init);
-static void drm_irq_vgaarb_nokms(void *cookie, bool state)
-{
- struct drm_device *dev = cookie;
-
- if (dev->driver->vgaarb_irq) {
- dev->driver->vgaarb_irq(dev, state);
- return;
- }
-
- if (!dev->irq_enabled)
- return;
-
- if (state) {
- if (dev->driver->irq_uninstall)
- dev->driver->irq_uninstall(dev);
- } else {
- if (dev->driver->irq_preinstall)
- dev->driver->irq_preinstall(dev);
- if (dev->driver->irq_postinstall)
- dev->driver->irq_postinstall(dev);
- }
-}
-
/**
* drm_irq_install - install IRQ handler
* @dev: DRM device
@@ -449,7 +426,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
*
* This is the simplified helper interface provided for drivers with no special
* needs. Drivers which need to install interrupt handlers for multiple
- * interrupts must instead set drm_device->irq_enabled to signal the DRM core
+ * interrupts must instead set &drm_device.irq_enabled to signal the DRM core
* that vblank interrupts are available.
*
* Returns:
@@ -492,9 +469,6 @@ int drm_irq_install(struct drm_device *dev, int irq)
return ret;
}
- if (drm_core_check_feature(dev, DRIVER_LEGACY))
- vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
-
/* After installing handler */
if (dev->driver->irq_postinstall)
ret = dev->driver->irq_postinstall(dev);
@@ -519,7 +493,7 @@ EXPORT_SYMBOL(drm_irq_install);
* Calls the driver's irq_uninstall() function and unregisters the IRQ handler.
* This should only be called by drivers which used drm_irq_install() to set up
* their interrupt handler. Other drivers must only reset
- * drm_device->irq_enabled to false.
+ * &drm_device.irq_enabled to false.
*
* Note that for kernel modesetting drivers it is a bug if this function fails.
* The sanity checks are only to catch buggy user modesetting drivers which call
@@ -982,12 +956,11 @@ static void send_vblank_event(struct drm_device *dev,
* period. This helper function implements exactly the required vblank arming
* behaviour.
*
- * NOTE: Drivers using this to send out the event in &struct drm_crtc_state
- * as part of an atomic commit must ensure that the next vblank happens at
- * exactly the same time as the atomic commit is committed to the hardware. This
- * function itself does **not** protect again the next vblank interrupt racing
- * with either this function call or the atomic commit operation. A possible
- * sequence could be:
+ * NOTE: Drivers using this to send out the &drm_crtc_state.event as part of an
+ * atomic commit must ensure that the next vblank happens at exactly the same
+ * time as the atomic commit is committed to the hardware. This function itself
+ * does **not** protect again the next vblank interrupt racing with either this
+ * function call or the atomic commit operation. A possible sequence could be:
*
* 1. Driver commits new hardware state into vblank-synchronized registers.
* 2. A vblank happens, committing the hardware state. Also the corresponding
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 229b3f525dee..e51876e588d6 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -552,8 +552,8 @@ EXPORT_SYMBOL(drm_mm_replace_node);
* objects to the roster, probably by walking an LRU list, but this can be
* freely implemented. Eviction candiates are added using
* drm_mm_scan_add_block() until a suitable hole is found or there are no
- * further evictable objects. Eviction roster metadata is tracked in struct
- * &drm_mm_scan.
+ * further evictable objects. Eviction roster metadata is tracked in &struct
+ * drm_mm_scan.
*
* The driver must walk through all objects again in exactly the reverse
* order to restore the allocator state. Note that while the allocator is used
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index ed1ee5a44a7b..884cc4d26fb5 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -421,7 +421,12 @@ void drm_mode_config_cleanup(struct drm_device *dev)
drm_connector_unreference(connector);
}
drm_connector_list_iter_put(&conn_iter);
- WARN_ON(!list_empty(&dev->mode_config.connector_list));
+ if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
+ drm_connector_list_iter_get(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter)
+ DRM_ERROR("connector %s leaked!\n", connector->name);
+ drm_connector_list_iter_put(&conn_iter);
+ }
list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
head) {
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index ac6a35212501..a8616b1a8d22 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -797,6 +797,26 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode)
EXPORT_SYMBOL(drm_mode_vrefresh);
/**
+ * drm_mode_get_hv_timing - Fetches hdisplay/vdisplay for given mode
+ * @mode: mode to query
+ * @hdisplay: hdisplay value to fill in
+ * @vdisplay: vdisplay value to fill in
+ *
+ * The vdisplay value will be doubled if the specified mode is a stereo mode of
+ * the appropriate layout.
+ */
+void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
+ int *hdisplay, int *vdisplay)
+{
+ struct drm_display_mode adjusted = *mode;
+
+ drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
+ *hdisplay = adjusted.crtc_hdisplay;
+ *vdisplay = adjusted.crtc_vdisplay;
+}
+EXPORT_SYMBOL(drm_mode_get_hv_timing);
+
+/**
* drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
* @p: mode
* @adjust_flags: a combination of adjustment flags
@@ -1460,6 +1480,13 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
return NULL;
mode->type |= DRM_MODE_TYPE_USERDEF;
+ /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */
+ if (cmd->xres == 1366 && mode->hdisplay == 1368) {
+ mode->hdisplay = 1366;
+ mode->hsync_start--;
+ mode->hsync_end--;
+ drm_mode_set_name(mode);
+ }
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
return mode;
}
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 3551ae31f143..bf60f2645e55 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -33,7 +33,7 @@
* to use &ww_mutex and acquire-contexts to avoid deadlocks. But because
* the locking is more distributed around the driver code, we want a bit
* of extra utility/tracking out of our acquire-ctx. This is provided
- * by drm_modeset_lock / drm_modeset_acquire_ctx.
+ * by &struct drm_modeset_lock and &struct drm_modeset_acquire_ctx.
*
* For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.txt
*
@@ -53,7 +53,7 @@
* drm_modeset_acquire_fini(&ctx);
*
* On top of of these per-object locks using &ww_mutex there's also an overall
- * dev->mode_config.lock, for protecting everything else. Mostly this means
+ * &drm_mode_config.mutex, for protecting everything else. Mostly this means
* probe state of connectors, and preventing hotplug add/removal of connectors.
*
* Finally there's a bunch of dedicated locks to protect drm core internal
@@ -71,7 +71,7 @@ static DEFINE_WW_CLASS(crtc_ww_class);
* drm_modeset_unlock_all() function.
*
* This function is deprecated. It allocates a lock acquisition context and
- * stores it in the DRM device's ->mode_config. This facilitate conversion of
+ * stores it in &drm_device.mode_config. This facilitate conversion of
* existing code because it removes the need to manually deal with the
* acquisition context, but it is also brittle because the context is global
* and care must be taken not to nest calls. New code should use the
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
* drm_modeset_lock_all() function.
*
* This function is deprecated. It uses the lock acquisition context stored
- * in the DRM device's ->mode_config. This facilitates conversion of existing
+ * in &drm_device.mode_config. This facilitates conversion of existing
* code because it removes the need to manually deal with the acquisition
* context, but it is also brittle because the context is global and care must
* be taken not to nest calls. New code should pass the acquisition context
@@ -468,7 +468,7 @@ EXPORT_SYMBOL(drm_modeset_unlock);
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented.
*
- * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex
+ * Unlike drm_modeset_lock_all(), it doesn't take the &drm_mode_config.mutex
* since that lock isn't required for modeset state changes. Callers which
* need to grab that lock too need to do so outside of the acquire context
* @ctx.
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index dc358f860aea..a3b356e70b35 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -191,7 +191,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
static void drm_pci_agp_init(struct drm_device *dev)
{
if (drm_core_check_feature(dev, DRIVER_USE_AGP)) {
- if (drm_pci_device_is_agp(dev))
+ if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
dev->agp = drm_agp_init(dev);
if (dev->agp) {
dev->agp->agp_mtrr = arch_phys_wc_add(
@@ -223,7 +223,7 @@ void drm_pci_agp_destroy(struct drm_device *dev)
* Try and register, if we fail to register, backout previous work.
*
* NOTE: This function is deprecated, please use drm_dev_alloc() and
- * drm_dev_register() instead and remove your ->load() callback.
+ * drm_dev_register() instead and remove your &drm_driver.load callback.
*
* Return: 0 on success or a negative error code on failure.
*/
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index eed66be18329..c464fc4a874d 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -42,7 +42,7 @@
*
* Cursor and overlay planes are optional. All drivers should provide one
* primary plane per CRTC to avoid surprising userspace too much. See enum
- * &drm_plane_type for a more in-depth discussion of these special uapi-relevant
+ * drm_plane_type for a more in-depth discussion of these special uapi-relevant
* plane types. Special planes are associated with their CRTC by calling
* drm_crtc_init_with_planes().
*
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 35d43607a47d..148688fb920a 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -39,9 +39,9 @@
*
* This helper library has two parts. The first part has support to implement
* primary plane support on top of the normal CRTC configuration interface.
- * Since the legacy ->set_config interface ties the primary plane together with
- * the CRTC state this does not allow userspace to disable the primary plane
- * itself. To avoid too much duplicated code use
+ * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
+ * plane together with the CRTC state this does not allow userspace to disable
+ * the primary plane itself. To avoid too much duplicated code use
* drm_plane_helper_check_update() which can be used to enforce the same
* restrictions as primary planes had thus. The default primary plane only
* expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
@@ -384,7 +384,8 @@ EXPORT_SYMBOL(drm_primary_helper_update);
* is called in response to a userspace SetPlane operation on the plane with a
* NULL framebuffer parameter. It unconditionally fails the disable call with
* -EINVAL the only way to disable the primary plane without driver support is
- * to disable the entier CRTC. Which does not match the plane ->disable hook.
+ * to disable the entire CRTC. Which does not match the plane
+ * &drm_plane_funcs.disable_plane hook.
*
* Note that some hardware may be able to disable the primary plane without
* disabling the whole CRTC. Drivers for such hardware should provide their
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 7af3005a030c..56d2f93ed6b9 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -74,7 +74,7 @@ err_free:
* .load() function.
*
* NOTE: This function is deprecated, please use drm_dev_alloc() and
- * drm_dev_register() instead and remove your ->load() callback.
+ * drm_dev_register() instead and remove your &drm_driver.load callback.
*
* Return: 0 on success or a negative error code on failure.
*/
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 8d77b2462594..25aa4558f1b5 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -40,8 +40,11 @@
* On the export the dma_buf holds a reference to the exporting GEM
* object. It takes this reference in handle_to_fd_ioctl, when it
* first calls .prime_export and stores the exporting GEM object in
- * the dma_buf priv. This reference is released when the dma_buf
- * object goes away in the driver .release function.
+ * the dma_buf priv. This reference needs to be released when the
+ * final reference to the &dma_buf itself is dropped and its
+ * &dma_buf_ops.release function is called. For GEM-based drivers,
+ * the dma_buf should be exported using drm_gem_dmabuf_export() and
+ * then released by drm_gem_dmabuf_release().
*
* On the import the importing GEM object holds a reference to the
* dma_buf (which in turn holds a ref to the exporting GEM object).
@@ -51,6 +54,16 @@
* when the imported object is destroyed, we remove the attachment
* and drop the reference to the dma_buf.
*
+ * When all the references to the &dma_buf are dropped, i.e. when
+ * userspace has closed both handles to the imported GEM object (through the
+ * FD_TO_HANDLE IOCTL) and closed the file descriptor of the exported
+ * (through the HANDLE_TO_FD IOCTL) dma_buf, and all kernel-internal references
+ * are also gone, then the dma_buf gets destroyed. This can also happen as a
+ * part of the clean up procedure in the drm_release() function if userspace
+ * fails to properly clean up. Note that both the kernel and userspace (by
+ * keeeping the PRIME file descriptors open) can hold references onto a
+ * &dma_buf.
+ *
* Thus the chain of references always flows in one direction
* (avoiding loops): importing_gem -> dmabuf -> exporting_gem
*
@@ -291,7 +304,7 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
* This wraps dma_buf_export() for use by generic GEM drivers that are using
* drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take
* a reference to the &drm_device and the exported &drm_gem_object (stored in
- * exp_info->priv) which is released by drm_gem_dmabuf_release().
+ * &dma_buf_export_info.priv) which is released by drm_gem_dmabuf_release().
*
* Returns the new dmabuf.
*/
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 97a32898ef50..93381454bdf7 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -43,7 +43,7 @@
* DOC: output probing helper overview
*
* This library provides some helper code for output probing. It provides an
- * implementation of the core connector->fill_modes interface with
+ * implementation of the core &drm_connector_funcs.fill_modes interface with
* drm_helper_probe_single_connector_modes.
*
* It also provides support for polling connectors with a work item and for
@@ -115,25 +115,28 @@ static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
/**
- * drm_kms_helper_poll_enable_locked - re-enable output polling.
+ * drm_kms_helper_poll_enable - re-enable output polling.
* @dev: drm_device
*
- * This function re-enables the output polling work without
- * locking the mode_config mutex.
+ * This function re-enables the output polling work, after it has been
+ * temporarily disabled using drm_kms_helper_poll_disable(), for example over
+ * suspend/resume.
*
- * This is like drm_kms_helper_poll_enable() however it is to be
- * called from a context where the mode_config mutex is locked
- * already.
+ * Drivers can call this helper from their device resume implementation. It is
+ * an error to call this when the output polling support has not yet been set
+ * up.
+ *
+ * Note that calls to enable and disable polling must be strictly ordered, which
+ * is automatically the case when they're only call from suspend/resume
+ * callbacks.
*/
-void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
+void drm_kms_helper_poll_enable(struct drm_device *dev)
{
bool poll = false;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
- WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
-
if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
return;
@@ -146,14 +149,24 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
drm_connector_list_iter_put(&conn_iter);
if (dev->mode_config.delayed_event) {
+ /*
+ * FIXME:
+ *
+ * Use short (1s) delay to handle the initial delayed event.
+ * This delay should not be needed, but Optimus/nouveau will
+ * fail in a mysterious way if the delayed event is handled as
+ * soon as possible like it is done in
+ * drm_helper_probe_single_connector_modes() in case the poll
+ * was enabled before.
+ */
poll = true;
- delay = 0;
+ delay = HZ;
}
if (poll)
schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
}
-EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked);
+EXPORT_SYMBOL(drm_kms_helper_poll_enable);
static enum drm_connector_status
drm_connector_detect(struct drm_connector *connector, bool force)
@@ -174,9 +187,9 @@ drm_connector_detect(struct drm_connector *connector, bool force)
* be added to the connector's probed_modes list, then culled (based on validity
* and the @maxX, @maxY parameters) and put into the normal modes list.
*
- * Intended to be used as a generic implementation of the ->fill_modes()
- * @connector vfunc for drivers that use the CRTC helpers for output mode
- * filtering and detection.
+ * Intended to be used as a generic implementation of the
+ * &drm_connector_funcs.fill_modes() vfunc for drivers that use the CRTC helpers
+ * for output mode filtering and detection.
*
* The basic procedure is as follows
*
@@ -188,7 +201,7 @@ drm_connector_detect(struct drm_connector *connector, bool force)
*
* - debugfs 'override_edid' (used for testing only)
* - firmware EDID (drm_load_edid_firmware())
- * - connector helper ->get_modes() vfunc
+ * - &drm_connector_helper_funcs.get_modes vfunc
* - if the connector status is connector_status_connected, standard
* VESA DMT modes up to 1024x768 are automatically added
* (drm_add_modes_noedid())
@@ -209,8 +222,8 @@ drm_connector_detect(struct drm_connector *connector, bool force)
* (if specified)
* - drm_mode_validate_flag() checks the modes againt basic connector
* capabilites (interlace_allowed,doublescan_allowed,stereo_allowed)
- * - the optional connector ->mode_valid() helper can perform driver and/or
- * hardware specific checks
+ * - the optional &drm_connector_helper_funcs.mode_valid helper can perform
+ * driver and/or hardware specific checks
*
* 5. Any mode whose status is not OK is pruned from the connector's modes list,
* accompanied by a debug message indicating the reason for the mode's
@@ -280,7 +293,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
/* Re-enable polling in case the global poll config changed. */
if (drm_kms_helper_poll != dev->mode_config.poll_running)
- drm_kms_helper_poll_enable_locked(dev);
+ drm_kms_helper_poll_enable(dev);
dev->mode_config.poll_running = drm_kms_helper_poll;
@@ -474,8 +487,12 @@ out:
* This function disables the output polling work.
*
* Drivers can call this helper from their device suspend implementation. It is
- * not an error to call this even when output polling isn't enabled or arlready
- * disabled.
+ * not an error to call this even when output polling isn't enabled or already
+ * disabled. Polling is re-enabled by calling drm_kms_helper_poll_enable().
+ *
+ * Note that calls to enable and disable polling must be strictly ordered, which
+ * is automatically the case when they're only call from suspend/resume
+ * callbacks.
*/
void drm_kms_helper_poll_disable(struct drm_device *dev)
{
@@ -486,24 +503,6 @@ void drm_kms_helper_poll_disable(struct drm_device *dev)
EXPORT_SYMBOL(drm_kms_helper_poll_disable);
/**
- * drm_kms_helper_poll_enable - re-enable output polling.
- * @dev: drm_device
- *
- * This function re-enables the output polling work.
- *
- * Drivers can call this helper from their device resume implementation. It is
- * an error to call this when the output polling support has not yet been set
- * up.
- */
-void drm_kms_helper_poll_enable(struct drm_device *dev)
-{
- mutex_lock(&dev->mode_config.mutex);
- drm_kms_helper_poll_enable_locked(dev);
- mutex_unlock(&dev->mode_config.mutex);
-}
-EXPORT_SYMBOL(drm_kms_helper_poll_enable);
-
-/**
* drm_kms_helper_poll_init - initialize and enable output polling
* @dev: drm_device
*
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
index 0d0e5dc0ee23..7fc070f3e49e 100644
--- a/drivers/gpu/drm/drm_property.c
+++ b/drivers/gpu/drm/drm_property.c
@@ -42,8 +42,8 @@
* drm_object_attach_property().
*
* Property values are only 64bit. To support bigger piles of data (like gamma
- * tables, color correction matrizes or large structures) a property can instead
- * point at a &drm_property_blob with that additional data
+ * tables, color correction matrices or large structures) a property can instead
+ * point at a &drm_property_blob with that additional data.
*
* Properties are defined by their symbolic name, userspace must keep a
* per-object mapping from those names to the property ID used in the atomic
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 9a37196c1bf1..513288b5c2f6 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -255,7 +255,7 @@ static const struct attribute_group *connector_dev_groups[] = {
* @connector: connector to add
*
* Create a connector device in sysfs, along with its associated connector
- * properties (so far, connection status, dpms, mode list & edid) and
+ * properties (so far, connection status, dpms, mode list and edid) and
* generate a hotplug event so userspace knows there's a new connector
* available.
*/
diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
index 2cde7a5442fb..cc1731c5289c 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -2,7 +2,8 @@
config DRM_ETNAVIV
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
depends on DRM
- depends on ARCH_MXC || ARCH_DOVE
+ depends on ARCH_MXC || ARCH_DOVE || (ARM && COMPILE_TEST)
+ depends on MMU
select SHMEM
select TMPFS
select IOMMU_API
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index b92c24e07cea..590be0d1dd95 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -258,12 +258,6 @@ static int etnaviv_debugfs_init(struct drm_minor *minor)
return ret;
}
-
-static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(etnaviv_debugfs_list,
- ARRAY_SIZE(etnaviv_debugfs_list), minor);
-}
#endif
/*
@@ -509,7 +503,6 @@ static struct drm_driver etnaviv_drm_driver = {
.gem_prime_mmap = etnaviv_gem_prime_mmap,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = etnaviv_debugfs_init,
- .debugfs_cleanup = etnaviv_debugfs_cleanup,
#endif
.ioctls = etnaviv_ioctls,
.num_ioctls = DRM_ETNAVIV_NUM_IOCTLS,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index ae2733a609ba..f503af462dad 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -117,9 +117,14 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
struct list_head list;
bool found;
+ /*
+ * XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick
+ * drm_mm into giving out a low IOVA after address space
+ * rollover. This needs a proper fix.
+ */
ret = drm_mm_insert_node_in_range(&mmu->mm, node,
size, 0, mmu->last_iova, ~0UL,
- DRM_MM_SEARCH_DEFAULT);
+ mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW);
if (ret != -ENOSPC)
break;
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index d706ca4e2f02..1d185347c64c 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -19,7 +19,6 @@ comment "CRTCs"
config DRM_EXYNOS_FIMD
bool "FIMD"
depends on !FB_S3C
- select FB_MODE_HELPERS
select MFD_SYSCON
help
Choose this option if you want to use Exynos FIMD for DRM.
@@ -32,7 +31,6 @@ config DRM_EXYNOS5433_DECON
config DRM_EXYNOS7_DECON
bool "DECON on Exynos7"
depends on !FB_S3C
- select FB_MODE_HELPERS
help
Choose this option if you want to use Exynos DECON for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index c5c01628c715..d69af00bdd6a 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -46,7 +46,8 @@ enum decon_flag_bits {
BIT_CLKS_ENABLED,
BIT_IRQS_ENABLED,
BIT_WIN_UPDATED,
- BIT_SUSPENDED
+ BIT_SUSPENDED,
+ BIT_REQUEST_UPDATE
};
struct decon_context {
@@ -141,12 +142,6 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
m->crtc_vsync_end = m->crtc_vsync_start + 1;
}
- decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0);
-
- /* enable clock gate */
- val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
- writel(val, ctx->addr + DECON_CMU);
-
if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))
decon_setup_trigger(ctx);
@@ -315,6 +310,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
/* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
+ set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
}
static void decon_disable_plane(struct exynos_drm_crtc *crtc,
@@ -327,6 +323,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
return;
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
+ set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
}
static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
@@ -340,8 +337,8 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_shadow_protect_win(ctx, i, false);
- /* standalone update */
- decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
+ if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags))
+ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
if (ctx->out_type & IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags);
@@ -470,7 +467,7 @@ err:
clk_disable_unprepare(ctx->clks[i]);
}
-static struct exynos_drm_crtc_ops decon_crtc_ops = {
+static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable = decon_enable,
.disable = decon_disable,
.enable_vblank = decon_enable_vblank,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 2530bf57716a..309c8ee52524 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -109,9 +109,6 @@ static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_private *private = crtc->dev->dev_private;
-
- private->crtc[exynos_crtc->pipe] = NULL;
drm_crtc_cleanup(crtc);
kfree(exynos_crtc);
@@ -134,7 +131,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
void *ctx)
{
struct exynos_drm_crtc *exynos_crtc;
- struct exynos_drm_private *private = drm_dev->dev_private;
struct drm_crtc *crtc;
int ret;
@@ -149,8 +145,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
crtc = &exynos_crtc->base;
- private->crtc[pipe] = crtc;
-
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
&exynos_crtc_funcs, NULL);
if (ret < 0)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 80c4d5b81689..cf6e08cb35a7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -211,12 +211,6 @@ struct drm_exynos_file_private {
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
- /*
- * created crtc object would be contained at this array and
- * this array is used to be aware of which crtc did it request vblank.
- */
- struct drm_crtc *crtc[MAX_CRTC];
-
struct device *dma_dev;
void *mapping;
@@ -231,9 +225,9 @@ struct exynos_drm_private {
static inline struct exynos_drm_crtc *
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
{
- struct exynos_drm_private *private = dev->dev_private;
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
- return to_exynos_crtc(private->crtc[pipe]);
+ return to_exynos_crtc(crtc);
}
static inline struct device *to_dma_dev(struct drm_device *dev)
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 0dc7ba2fdc22..5ee93ff55608 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -406,11 +406,6 @@ out_err:
return ret;
}
-static int psb_driver_device_is_agp(struct drm_device *dev)
-{
- return 0;
-}
-
static inline void get_brightness(struct backlight_device *bd)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
@@ -487,7 +482,6 @@ static struct drm_driver driver = {
.set_busid = drm_pci_set_busid,
.num_ioctls = ARRAY_SIZE(psb_ioctls),
- .device_is_agp = psb_driver_device_is_agp,
.irq_preinstall = psb_irq_preinstall,
.irq_postinstall = psb_irq_postinstall,
.irq_uninstall = psb_irq_uninstall,
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
index 7a6957ae4b44..16fe79053ee1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -121,7 +121,7 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
if (IS_ERR(hi_fbdev->fb)) {
- ret = PTR_ERR(info);
+ ret = PTR_ERR(hi_fbdev->fb);
DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
goto out_release_fbi;
}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 3c6f750389fb..20732b62d4c9 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -243,8 +243,6 @@ struct ttm_bo_driver hibmc_bo_driver = {
.verify_access = hibmc_bo_verify_access,
.io_mem_reserve = &hibmc_ttm_io_mem_reserve,
.io_mem_free = NULL,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int hibmc_mm_init(struct hibmc_drm_private *hibmc)
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index 307d460ab684..9a0678a33e0d 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -304,8 +304,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
- struct kirin_drm_private *priv = dev->dev_private;
- struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
@@ -320,8 +320,8 @@ static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
- struct kirin_drm_private *priv = dev->dev_private;
- struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
@@ -575,7 +575,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = {
static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *plane)
{
- struct kirin_drm_private *priv = dev->dev_private;
struct device_node *port;
int ret;
@@ -599,7 +598,6 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
}
drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
- priv->crtc[drm_crtc_index(crtc)] = crtc;
return 0;
}
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
index a0bb217c4c64..7f60c64915d9 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
@@ -20,7 +20,6 @@ struct kirin_dc_ops {
};
struct kirin_drm_private {
- struct drm_crtc *crtc[MAX_CRTC];
#ifdef CONFIG_DRM_FBDEV_EMULATION
struct drm_fbdev_cma *fbdev;
#endif
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index ab4e6cbe1f8b..576a417690d4 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -1190,6 +1190,14 @@ static int i810_flip_bufs(struct drm_device *dev, void *data,
int i810_driver_load(struct drm_device *dev, unsigned long flags)
{
+ dev->agp = drm_agp_init(dev);
+ if (dev->agp) {
+ dev->agp->agp_mtrr = arch_phys_wc_add(
+ dev->agp->agp_info.aper_base,
+ dev->agp->agp_info.aper_size *
+ 1024 * 1024);
+ }
+
/* Our userspace depends upon the agp mapping support. */
if (!dev->agp)
return -EINVAL;
@@ -1249,19 +1257,3 @@ const struct drm_ioctl_desc i810_ioctls[] = {
};
int i810_max_ioctl = ARRAY_SIZE(i810_ioctls);
-
-/**
- * Determine if the device really is AGP or not.
- *
- * All Intel graphics chipsets are treated as AGP, even if they are really
- * PCI-e.
- *
- * \param dev The device to be tested.
- *
- * \returns
- * A value of 1 is always retured to indictate every i810 is AGP.
- */
-int i810_driver_device_is_agp(struct drm_device *dev)
-{
- return 1;
-}
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
index 02504a7cfaf2..37fd0906f807 100644
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ b/drivers/gpu/drm/i810/i810_drv.c
@@ -60,7 +60,6 @@ static struct drm_driver driver = {
.lastclose = i810_driver_lastclose,
.preclose = i810_driver_preclose,
.set_busid = drm_pci_set_busid,
- .device_is_agp = i810_driver_device_is_agp,
.dma_quiescent = i810_driver_dma_quiescent,
.ioctls = i810_ioctls,
.fops = &i810_driver_fops,
diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h
index 93ec5dc4e7d3..c73d2f2da57b 100644
--- a/drivers/gpu/drm/i810/i810_drv.h
+++ b/drivers/gpu/drm/i810/i810_drv.h
@@ -124,7 +124,6 @@ extern int i810_driver_load(struct drm_device *, unsigned long flags);
extern void i810_driver_lastclose(struct drm_device *dev);
extern void i810_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv);
-extern int i810_driver_device_is_agp(struct drm_device *dev);
extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern const struct drm_ioctl_desc i810_ioctls[];
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5196509e71cf..74ca2e8b2494 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -56,7 +56,9 @@ i915-y += i915_cmd_parser.o \
# general-purpose microcontroller (GuC) support
i915-y += intel_uc.o \
+ intel_guc_log.o \
intel_guc_loader.o \
+ intel_huc.o \
i915_guc_submission.o
# autogenerated null render state
diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c
index 7d33b607bc89..7311aeab16f7 100644
--- a/drivers/gpu/drm/i915/gvt/aperture_gm.c
+++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c
@@ -37,58 +37,38 @@
#include "i915_drv.h"
#include "gvt.h"
-#define MB_TO_BYTES(mb) ((mb) << 20ULL)
-#define BYTES_TO_MB(b) ((b) >> 20ULL)
-
-#define HOST_LOW_GM_SIZE MB_TO_BYTES(128)
-#define HOST_HIGH_GM_SIZE MB_TO_BYTES(384)
-#define HOST_FENCE 4
-
static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm)
{
struct intel_gvt *gvt = vgpu->gvt;
struct drm_i915_private *dev_priv = gvt->dev_priv;
- u32 alloc_flag, search_flag;
+ unsigned int flags;
u64 start, end, size;
struct drm_mm_node *node;
- int retried = 0;
int ret;
if (high_gm) {
- search_flag = DRM_MM_SEARCH_BELOW;
- alloc_flag = DRM_MM_CREATE_TOP;
node = &vgpu->gm.high_gm_node;
size = vgpu_hidden_sz(vgpu);
start = gvt_hidden_gmadr_base(gvt);
end = gvt_hidden_gmadr_end(gvt);
+ flags = PIN_HIGH;
} else {
- search_flag = DRM_MM_SEARCH_DEFAULT;
- alloc_flag = DRM_MM_CREATE_DEFAULT;
node = &vgpu->gm.low_gm_node;
size = vgpu_aperture_sz(vgpu);
start = gvt_aperture_gmadr_base(gvt);
end = gvt_aperture_gmadr_end(gvt);
+ flags = PIN_MAPPABLE;
}
mutex_lock(&dev_priv->drm.struct_mutex);
-search_again:
- ret = drm_mm_insert_node_in_range_generic(&dev_priv->ggtt.base.mm,
- node, size, 4096,
- I915_COLOR_UNEVICTABLE,
- start, end, search_flag,
- alloc_flag);
- if (ret) {
- ret = i915_gem_evict_something(&dev_priv->ggtt.base,
- size, 4096,
- I915_COLOR_UNEVICTABLE,
- start, end, 0);
- if (ret == 0 && ++retried < 3)
- goto search_again;
-
- gvt_err("fail to alloc %s gm space from host, retried %d\n",
- high_gm ? "high" : "low", retried);
- }
+ ret = i915_gem_gtt_insert(&dev_priv->ggtt.base, node,
+ size, 4096, I915_COLOR_UNEVICTABLE,
+ start, end, flags);
mutex_unlock(&dev_priv->drm.struct_mutex);
+ if (ret)
+ gvt_err("fail to alloc %s gm space from host\n",
+ high_gm ? "high" : "low");
+
return ret;
}
@@ -168,6 +148,14 @@ void intel_vgpu_write_fence(struct intel_vgpu *vgpu,
POSTING_READ(fence_reg_lo);
}
+static void _clear_vgpu_fence(struct intel_vgpu *vgpu)
+{
+ int i;
+
+ for (i = 0; i < vgpu_fence_sz(vgpu); i++)
+ intel_vgpu_write_fence(vgpu, i, 0);
+}
+
static void free_vgpu_fence(struct intel_vgpu *vgpu)
{
struct intel_gvt *gvt = vgpu->gvt;
@@ -181,9 +169,9 @@ static void free_vgpu_fence(struct intel_vgpu *vgpu)
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->drm.struct_mutex);
+ _clear_vgpu_fence(vgpu);
for (i = 0; i < vgpu_fence_sz(vgpu); i++) {
reg = vgpu->fence.regs[i];
- intel_vgpu_write_fence(vgpu, i, 0);
list_add_tail(&reg->link,
&dev_priv->mm.fence_list);
}
@@ -211,13 +199,14 @@ static int alloc_vgpu_fence(struct intel_vgpu *vgpu)
continue;
list_del(pos);
vgpu->fence.regs[i] = reg;
- intel_vgpu_write_fence(vgpu, i, 0);
if (++i == vgpu_fence_sz(vgpu))
break;
}
if (i != vgpu_fence_sz(vgpu))
goto out_free_fence;
+ _clear_vgpu_fence(vgpu);
+
mutex_unlock(&dev_priv->drm.struct_mutex);
intel_runtime_pm_put(dev_priv);
return 0;
@@ -317,6 +306,22 @@ void intel_vgpu_free_resource(struct intel_vgpu *vgpu)
}
/**
+ * intel_vgpu_reset_resource - reset resource state owned by a vGPU
+ * @vgpu: a vGPU
+ *
+ * This function is used to reset resource state owned by a vGPU.
+ *
+ */
+void intel_vgpu_reset_resource(struct intel_vgpu *vgpu)
+{
+ struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+
+ intel_runtime_pm_get(dev_priv);
+ _clear_vgpu_fence(vgpu);
+ intel_runtime_pm_put(dev_priv);
+}
+
+/**
* intel_alloc_vgpu_resource - allocate HW resource for a vGPU
* @vgpu: vGPU
* @param: vGPU creation params
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c
index 711c31c8d8b4..4a6a2ed65732 100644
--- a/drivers/gpu/drm/i915/gvt/cfg_space.c
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -282,3 +282,77 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
}
return 0;
}
+
+/**
+ * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU
+ *
+ * @vgpu: a vGPU
+ * @primary: is the vGPU presented as primary
+ *
+ */
+void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
+ bool primary)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ const struct intel_gvt_device_info *info = &gvt->device_info;
+ u16 *gmch_ctl;
+ int i;
+
+ memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
+ info->cfg_space_size);
+
+ if (!primary) {
+ vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+ vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+ }
+
+ /* Show guest that there isn't any stolen memory.*/
+ gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
+ *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
+
+ intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
+ gvt_aperture_pa_base(gvt), true);
+
+ vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
+ | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER);
+ /*
+ * Clear the bar upper 32bit and let guest to assign the new value
+ */
+ memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
+ memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
+ memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
+
+ for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) {
+ vgpu->cfg_space.bar[i].size = pci_resource_len(
+ gvt->dev_priv->drm.pdev, i * 2);
+ vgpu->cfg_space.bar[i].tracked = false;
+ }
+}
+
+/**
+ * intel_vgpu_reset_cfg_space - reset vGPU configuration space
+ *
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu)
+{
+ u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND];
+ bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] !=
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+
+ if (cmd & PCI_COMMAND_MEMORY) {
+ trap_gttmmio(vgpu, false);
+ map_aperture(vgpu, false);
+ }
+
+ /**
+ * Currently we only do such reset when vGPU is not
+ * owned by any VM, so we simply restore entire cfg
+ * space to default value.
+ */
+ intel_vgpu_init_cfg_space(vgpu, primary);
+}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
index 6c5fdf5b2ce2..47dec4acf7ff 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.c
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -240,15 +240,8 @@ static inline int get_pse_type(int type)
static u64 read_pte64(struct drm_i915_private *dev_priv, unsigned long index)
{
void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index;
- u64 pte;
-#ifdef readq
- pte = readq(addr);
-#else
- pte = ioread32(addr);
- pte |= (u64)ioread32(addr + 4) << 32;
-#endif
- return pte;
+ return readq(addr);
}
static void write_pte64(struct drm_i915_private *dev_priv,
@@ -256,12 +249,8 @@ static void write_pte64(struct drm_i915_private *dev_priv,
{
void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index;
-#ifdef writeq
writeq(pte, addr);
-#else
- iowrite32((u32)pte, addr);
- iowrite32(pte >> 32, addr + 4);
-#endif
+
I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
POSTING_READ(GFX_FLSH_CNTL_GEN6);
}
@@ -1380,8 +1369,7 @@ static int gen8_mm_alloc_page_table(struct intel_vgpu_mm *mm)
info->gtt_entry_size;
mem = kzalloc(mm->has_shadow_page_table ?
mm->page_table_entry_size * 2
- : mm->page_table_entry_size,
- GFP_ATOMIC);
+ : mm->page_table_entry_size, GFP_KERNEL);
if (!mem)
return -ENOMEM;
mm->virtual_page_table = mem;
@@ -1532,7 +1520,7 @@ struct intel_vgpu_mm *intel_vgpu_create_mm(struct intel_vgpu *vgpu,
struct intel_vgpu_mm *mm;
int ret;
- mm = kzalloc(sizeof(*mm), GFP_ATOMIC);
+ mm = kzalloc(sizeof(*mm), GFP_KERNEL);
if (!mm) {
ret = -ENOMEM;
goto fail;
@@ -1886,30 +1874,27 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu,
struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
int page_entry_num = GTT_PAGE_SIZE >>
vgpu->gvt->device_info.gtt_entry_size_shift;
- struct page *scratch_pt;
+ void *scratch_pt;
unsigned long mfn;
int i;
- void *p;
if (WARN_ON(type < GTT_TYPE_PPGTT_PTE_PT || type >= GTT_TYPE_MAX))
return -EINVAL;
- scratch_pt = alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO);
+ scratch_pt = (void *)get_zeroed_page(GFP_KERNEL);
if (!scratch_pt) {
gvt_err("fail to allocate scratch page\n");
return -ENOMEM;
}
- p = kmap_atomic(scratch_pt);
- mfn = intel_gvt_hypervisor_virt_to_mfn(p);
+ mfn = intel_gvt_hypervisor_virt_to_mfn(scratch_pt);
if (mfn == INTEL_GVT_INVALID_ADDR) {
- gvt_err("fail to translate vaddr:0x%llx\n", (u64)p);
- kunmap_atomic(p);
- __free_page(scratch_pt);
+ gvt_err("fail to translate vaddr:0x%lx\n", (unsigned long)scratch_pt);
+ free_page((unsigned long)scratch_pt);
return -EFAULT;
}
gtt->scratch_pt[type].page_mfn = mfn;
- gtt->scratch_pt[type].page = scratch_pt;
+ gtt->scratch_pt[type].page = virt_to_page(scratch_pt);
gvt_dbg_mm("vgpu%d create scratch_pt: type %d mfn=0x%lx\n",
vgpu->id, type, mfn);
@@ -1918,7 +1903,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu,
* scratch_pt[type] indicate the scratch pt/scratch page used by the
* 'type' pt.
* e.g. scratch_pt[GTT_TYPE_PPGTT_PDE_PT] is used by
- * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scatch_pt it self
+ * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self
* is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn.
*/
if (type > GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX) {
@@ -1936,11 +1921,9 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu,
se.val64 |= PPAT_CACHED_INDEX;
for (i = 0; i < page_entry_num; i++)
- ops->set_entry(p, &se, i, false, 0, vgpu);
+ ops->set_entry(scratch_pt, &se, i, false, 0, vgpu);
}
- kunmap_atomic(p);
-
return 0;
}
@@ -2208,7 +2191,7 @@ int intel_vgpu_g2v_destroy_ppgtt_mm(struct intel_vgpu *vgpu,
int intel_gvt_init_gtt(struct intel_gvt *gvt)
{
int ret;
- void *page_addr;
+ void *page;
gvt_dbg_core("init gtt\n");
@@ -2221,17 +2204,14 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt)
return -ENODEV;
}
- gvt->gtt.scratch_ggtt_page =
- alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO);
- if (!gvt->gtt.scratch_ggtt_page) {
+ page = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!page) {
gvt_err("fail to allocate scratch ggtt page\n");
return -ENOMEM;
}
+ gvt->gtt.scratch_ggtt_page = virt_to_page(page);
- page_addr = page_address(gvt->gtt.scratch_ggtt_page);
-
- gvt->gtt.scratch_ggtt_mfn =
- intel_gvt_hypervisor_virt_to_mfn(page_addr);
+ gvt->gtt.scratch_ggtt_mfn = intel_gvt_hypervisor_virt_to_mfn(page);
if (gvt->gtt.scratch_ggtt_mfn == INTEL_GVT_INVALID_ADDR) {
gvt_err("fail to translate scratch ggtt page\n");
__free_page(gvt->gtt.scratch_ggtt_page);
@@ -2297,3 +2277,30 @@ void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu)
for (offset = 0; offset < num_entries; offset++)
ops->set_entry(NULL, &e, index + offset, false, 0, vgpu);
}
+
+/**
+ * intel_vgpu_reset_gtt - reset the all GTT related status
+ * @vgpu: a vGPU
+ * @dmlr: true for vGPU Device Model Level Reset, false for GT Reset
+ *
+ * This function is called from vfio core to reset reset all
+ * GTT related status, including GGTT, PPGTT, scratch page.
+ *
+ */
+void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr)
+{
+ int i;
+
+ ppgtt_free_all_shadow_page(vgpu);
+ if (!dmlr)
+ return;
+
+ intel_vgpu_reset_ggtt(vgpu);
+
+ /* clear scratch page for security */
+ for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
+ if (vgpu->gtt.scratch_pt[i].page != NULL)
+ memset(page_address(vgpu->gtt.scratch_pt[i].page),
+ 0, PAGE_SIZE);
+ }
+}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h
index b315ab3593ec..f88eb5e89bea 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.h
+++ b/drivers/gpu/drm/i915/gvt/gtt.h
@@ -208,6 +208,7 @@ extern void intel_vgpu_clean_gtt(struct intel_vgpu *vgpu);
void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu);
extern int intel_gvt_init_gtt(struct intel_gvt *gvt);
+extern void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr);
extern void intel_gvt_clean_gtt(struct intel_gvt *gvt);
extern struct intel_vgpu_mm *intel_gvt_find_ppgtt_mm(struct intel_vgpu *vgpu,
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 398877c3d2fd..e6bf5c533fbe 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -201,6 +201,8 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev, gvt);
intel_gvt_clean_vgpu_types(gvt);
+ idr_destroy(&gvt->vgpu_idr);
+
kfree(dev_priv->gvt);
dev_priv->gvt = NULL;
}
@@ -237,6 +239,8 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
gvt_dbg_core("init gvt device\n");
+ idr_init(&gvt->vgpu_idr);
+
mutex_init(&gvt->lock);
gvt->dev_priv = dev_priv;
@@ -244,7 +248,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
ret = intel_gvt_setup_mmio_info(gvt);
if (ret)
- return ret;
+ goto out_clean_idr;
ret = intel_gvt_load_firmware(gvt);
if (ret)
@@ -313,6 +317,8 @@ out_free_firmware:
intel_gvt_free_firmware(gvt);
out_clean_mmio_info:
intel_gvt_clean_mmio_info(gvt);
+out_clean_idr:
+ idr_destroy(&gvt->vgpu_idr);
kfree(gvt);
return ret;
}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 0af17016f33f..e227caf5859e 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -323,6 +323,7 @@ struct intel_vgpu_creation_params {
int intel_vgpu_alloc_resource(struct intel_vgpu *vgpu,
struct intel_vgpu_creation_params *param);
+void intel_vgpu_reset_resource(struct intel_vgpu *vgpu);
void intel_vgpu_free_resource(struct intel_vgpu *vgpu);
void intel_vgpu_write_fence(struct intel_vgpu *vgpu,
u32 fence, u64 value);
@@ -375,6 +376,8 @@ void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt);
struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
struct intel_vgpu_type *type);
void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu);
+void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
+ unsigned int engine_mask);
void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu);
@@ -411,6 +414,10 @@ int intel_gvt_ggtt_index_g2h(struct intel_vgpu *vgpu, unsigned long g_index,
int intel_gvt_ggtt_h2g_index(struct intel_vgpu *vgpu, unsigned long h_index,
unsigned long *g_index);
+void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
+ bool primary);
+void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu);
+
int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes);
@@ -424,7 +431,6 @@ void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu);
int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa);
int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci);
-int setup_vgpu_mmio(struct intel_vgpu *vgpu);
void populate_pvinfo_page(struct intel_vgpu *vgpu);
struct intel_gvt_ops {
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 57fb8e3cbd1f..1d450627ff65 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -93,7 +93,8 @@ static void write_vreg(struct intel_vgpu *vgpu, unsigned int offset,
static int new_mmio_info(struct intel_gvt *gvt,
u32 offset, u32 flags, u32 size,
u32 addr_mask, u32 ro_mask, u32 device,
- void *read, void *write)
+ int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int),
+ int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int))
{
struct intel_gvt_mmio_info *info, *p;
u32 start, end, i;
@@ -219,7 +220,7 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu,
default:
/*should not hit here*/
gvt_err("invalid forcewake offset 0x%x\n", offset);
- return 1;
+ return -EINVAL;
}
} else {
ack_reg_offset = FORCEWAKE_ACK_HSW_REG;
@@ -230,77 +231,45 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu,
return 0;
}
-static int handle_device_reset(struct intel_vgpu *vgpu, unsigned int offset,
- void *p_data, unsigned int bytes, unsigned long bitmap)
-{
- struct intel_gvt_workload_scheduler *scheduler =
- &vgpu->gvt->scheduler;
-
- vgpu->resetting = true;
-
- intel_vgpu_stop_schedule(vgpu);
- /*
- * The current_vgpu will set to NULL after stopping the
- * scheduler when the reset is triggered by current vgpu.
- */
- if (scheduler->current_vgpu == NULL) {
- mutex_unlock(&vgpu->gvt->lock);
- intel_gvt_wait_vgpu_idle(vgpu);
- mutex_lock(&vgpu->gvt->lock);
- }
-
- intel_vgpu_reset_execlist(vgpu, bitmap);
-
- /* full GPU reset */
- if (bitmap == 0xff) {
- mutex_unlock(&vgpu->gvt->lock);
- intel_vgpu_clean_gtt(vgpu);
- mutex_lock(&vgpu->gvt->lock);
- setup_vgpu_mmio(vgpu);
- populate_pvinfo_page(vgpu);
- intel_vgpu_init_gtt(vgpu);
- }
-
- vgpu->resetting = false;
-
- return 0;
-}
-
static int gdrst_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
- void *p_data, unsigned int bytes)
+ void *p_data, unsigned int bytes)
{
+ unsigned int engine_mask = 0;
u32 data;
- u64 bitmap = 0;
write_vreg(vgpu, offset, p_data, bytes);
data = vgpu_vreg(vgpu, offset);
if (data & GEN6_GRDOM_FULL) {
gvt_dbg_mmio("vgpu%d: request full GPU reset\n", vgpu->id);
- bitmap = 0xff;
- }
- if (data & GEN6_GRDOM_RENDER) {
- gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id);
- bitmap |= (1 << RCS);
- }
- if (data & GEN6_GRDOM_MEDIA) {
- gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id);
- bitmap |= (1 << VCS);
- }
- if (data & GEN6_GRDOM_BLT) {
- gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id);
- bitmap |= (1 << BCS);
- }
- if (data & GEN6_GRDOM_VECS) {
- gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id);
- bitmap |= (1 << VECS);
- }
- if (data & GEN8_GRDOM_MEDIA2) {
- gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id);
- if (HAS_BSD2(vgpu->gvt->dev_priv))
- bitmap |= (1 << VCS2);
+ engine_mask = ALL_ENGINES;
+ } else {
+ if (data & GEN6_GRDOM_RENDER) {
+ gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id);
+ engine_mask |= (1 << RCS);
+ }
+ if (data & GEN6_GRDOM_MEDIA) {
+ gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id);
+ engine_mask |= (1 << VCS);
+ }
+ if (data & GEN6_GRDOM_BLT) {
+ gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id);
+ engine_mask |= (1 << BCS);
+ }
+ if (data & GEN6_GRDOM_VECS) {
+ gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id);
+ engine_mask |= (1 << VECS);
+ }
+ if (data & GEN8_GRDOM_MEDIA2) {
+ gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id);
+ if (HAS_BSD2(vgpu->gvt->dev_priv))
+ engine_mask |= (1 << VCS2);
+ }
}
- return handle_device_reset(vgpu, offset, p_data, bytes, bitmap);
+
+ intel_gvt_reset_vgpu_locked(vgpu, false, engine_mask);
+
+ return 0;
}
static int gmbus_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
@@ -974,7 +943,7 @@ static int sbi_data_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
return 0;
}
-static bool sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
+static int sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
u32 data;
@@ -1366,7 +1335,6 @@ static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu,
unsigned int offset, void *p_data, unsigned int bytes)
{
- int rc = 0;
unsigned int id = 0;
write_vreg(vgpu, offset, p_data, bytes);
@@ -1389,12 +1357,11 @@ static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu,
id = VECS;
break;
default:
- rc = -EINVAL;
- break;
+ return -EINVAL;
}
set_bit(id, (void *)vgpu->tlb_handle_pending);
- return rc;
+ return 0;
}
static int ring_reset_ctl_write(struct intel_vgpu *vgpu,
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index faaae07ae487..0c9234a87a20 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -398,6 +398,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
struct intel_vgpu_type *type;
struct device *pdev;
void *gvt;
+ int ret;
pdev = mdev_parent_dev(mdev);
gvt = kdev_to_i915(pdev)->gvt;
@@ -406,13 +407,15 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
if (!type) {
gvt_err("failed to find type %s to create\n",
kobject_name(kobj));
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
vgpu = intel_gvt_ops->vgpu_create(gvt, type);
if (IS_ERR_OR_NULL(vgpu)) {
- gvt_err("create intel vgpu failed\n");
- return -EINVAL;
+ ret = vgpu == NULL ? -EFAULT : PTR_ERR(vgpu);
+ gvt_err("failed to create intel vgpu: %d\n", ret);
+ goto out;
}
INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work);
@@ -422,7 +425,10 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
dev_name(mdev_dev(mdev)));
- return 0;
+ ret = 0;
+
+out:
+ return ret;
}
static int intel_vgpu_remove(struct mdev_device *mdev)
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 09c9450a1946..4df078bc5d04 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -125,25 +125,12 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1)))
goto err;
- mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
- if (!mmio && !vgpu->mmio.disable_warn_untrack) {
- gvt_err("vgpu%d: read untracked MMIO %x len %d val %x\n",
- vgpu->id, offset, bytes, *(u32 *)p_data);
-
- if (offset == 0x206c) {
- gvt_err("------------------------------------------\n");
- gvt_err("vgpu%d: likely triggers a gfx reset\n",
- vgpu->id);
- gvt_err("------------------------------------------\n");
- vgpu->mmio.disable_warn_untrack = true;
- }
- }
-
if (!intel_gvt_mmio_is_unalign(gvt, offset)) {
if (WARN_ON(!IS_ALIGNED(offset, bytes)))
goto err;
}
+ mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
if (mmio) {
if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
@@ -152,9 +139,23 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
goto err;
}
ret = mmio->read(vgpu, offset, p_data, bytes);
- } else
+ } else {
ret = intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);
+ if (!vgpu->mmio.disable_warn_untrack) {
+ gvt_err("vgpu%d: read untracked MMIO %x(%dB) val %x\n",
+ vgpu->id, offset, bytes, *(u32 *)p_data);
+
+ if (offset == 0x206c) {
+ gvt_err("------------------------------------------\n");
+ gvt_err("vgpu%d: likely triggers a gfx reset\n",
+ vgpu->id);
+ gvt_err("------------------------------------------\n");
+ vgpu->mmio.disable_warn_untrack = true;
+ }
+ }
+ }
+
if (ret)
goto err;
@@ -302,3 +303,56 @@ err:
mutex_unlock(&gvt->lock);
return ret;
}
+
+
+/**
+ * intel_vgpu_reset_mmio - reset virtual MMIO space
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ const struct intel_gvt_device_info *info = &gvt->device_info;
+
+ memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size);
+ memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size);
+
+ vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;
+
+ /* set the bit 0:2(Core C-State ) to C0 */
+ vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0;
+}
+
+/**
+ * intel_vgpu_init_mmio - init MMIO space
+ * @vgpu: a vGPU
+ *
+ * Returns:
+ * Zero on success, negative error code if failed
+ */
+int intel_vgpu_init_mmio(struct intel_vgpu *vgpu)
+{
+ const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
+
+ vgpu->mmio.vreg = vzalloc(info->mmio_size * 2);
+ if (!vgpu->mmio.vreg)
+ return -ENOMEM;
+
+ vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size;
+
+ intel_vgpu_reset_mmio(vgpu);
+
+ return 0;
+}
+
+/**
+ * intel_vgpu_clean_mmio - clean MMIO space
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu)
+{
+ vfree(vgpu->mmio.vreg);
+ vgpu->mmio.vreg = vgpu->mmio.sreg = NULL;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
index 87d5b5e366a3..3bc620f56f35 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.h
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -86,6 +86,10 @@ struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
*offset; \
})
+int intel_vgpu_init_mmio(struct intel_vgpu *vgpu);
+void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu);
+void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu);
+
int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa);
int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa,
diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c
index 81cd921770c6..d9fb41ab7119 100644
--- a/drivers/gpu/drm/i915/gvt/opregion.c
+++ b/drivers/gpu/drm/i915/gvt/opregion.c
@@ -36,9 +36,9 @@ static int init_vgpu_opregion(struct intel_vgpu *vgpu, u32 gpa)
vgpu->id))
return -EINVAL;
- vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_ATOMIC |
- GFP_DMA32 | __GFP_ZERO,
- INTEL_GVT_OPREGION_PORDER);
+ vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL |
+ __GFP_ZERO,
+ get_order(INTEL_GVT_OPREGION_SIZE));
if (!vgpu_opregion(vgpu)->va)
return -ENOMEM;
@@ -97,7 +97,7 @@ void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu)
if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) {
map_vgpu_opregion(vgpu, false);
free_pages((unsigned long)vgpu_opregion(vgpu)->va,
- INTEL_GVT_OPREGION_PORDER);
+ get_order(INTEL_GVT_OPREGION_SIZE));
vgpu_opregion(vgpu)->va = NULL;
}
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 0dfe789d8f02..fbd023a16f18 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -50,8 +50,7 @@
#define INTEL_GVT_OPREGION_PARM 0x204
#define INTEL_GVT_OPREGION_PAGES 2
-#define INTEL_GVT_OPREGION_PORDER 1
-#define INTEL_GVT_OPREGION_SIZE (2 * 4096)
+#define INTEL_GVT_OPREGION_SIZE (INTEL_GVT_OPREGION_PAGES * PAGE_SIZE)
#define VGT_SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _PLANE_STRIDE_2_B)
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index fd2b026f7ecd..7ea68a75dc46 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -350,13 +350,15 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
{
struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
struct intel_vgpu_workload *workload;
+ struct intel_vgpu *vgpu;
int event;
mutex_lock(&gvt->lock);
workload = scheduler->current_workload[ring_id];
+ vgpu = workload->vgpu;
- if (!workload->status && !workload->vgpu->resetting) {
+ if (!workload->status && !vgpu->resetting) {
wait_event(workload->shadow_ctx_status_wq,
!atomic_read(&workload->shadow_ctx_active));
@@ -364,8 +366,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
for_each_set_bit(event, workload->pending_events,
INTEL_GVT_EVENT_MAX)
- intel_vgpu_trigger_virtual_event(workload->vgpu,
- event);
+ intel_vgpu_trigger_virtual_event(vgpu, event);
}
gvt_dbg_sched("ring id %d complete workload %p status %d\n",
@@ -373,11 +374,10 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
scheduler->current_workload[ring_id] = NULL;
- atomic_dec(&workload->vgpu->running_workload_num);
-
list_del_init(&workload->list);
workload->complete(workload);
+ atomic_dec(&vgpu->running_workload_num);
wake_up(&scheduler->workload_complete_wq);
mutex_unlock(&gvt->lock);
}
@@ -459,11 +459,11 @@ complete:
gvt_dbg_sched("will complete workload %p\n, status: %d\n",
workload, workload->status);
- complete_current_workload(gvt, ring_id);
-
if (workload->req)
i915_gem_request_put(fetch_and_zero(&workload->req));
+ complete_current_workload(gvt, ring_id);
+
if (need_force_wake)
intel_uncore_forcewake_put(gvt->dev_priv,
FORCEWAKE_ALL);
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index 536d2b9d5777..7295bc8e12fb 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -35,79 +35,6 @@
#include "gvt.h"
#include "i915_pvinfo.h"
-static void clean_vgpu_mmio(struct intel_vgpu *vgpu)
-{
- vfree(vgpu->mmio.vreg);
- vgpu->mmio.vreg = vgpu->mmio.sreg = NULL;
-}
-
-int setup_vgpu_mmio(struct intel_vgpu *vgpu)
-{
- struct intel_gvt *gvt = vgpu->gvt;
- const struct intel_gvt_device_info *info = &gvt->device_info;
-
- if (vgpu->mmio.vreg)
- memset(vgpu->mmio.vreg, 0, info->mmio_size * 2);
- else {
- vgpu->mmio.vreg = vzalloc(info->mmio_size * 2);
- if (!vgpu->mmio.vreg)
- return -ENOMEM;
- }
-
- vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size;
-
- memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size);
- memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size);
-
- vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;
-
- /* set the bit 0:2(Core C-State ) to C0 */
- vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0;
- return 0;
-}
-
-static void setup_vgpu_cfg_space(struct intel_vgpu *vgpu,
- struct intel_vgpu_creation_params *param)
-{
- struct intel_gvt *gvt = vgpu->gvt;
- const struct intel_gvt_device_info *info = &gvt->device_info;
- u16 *gmch_ctl;
- int i;
-
- memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
- info->cfg_space_size);
-
- if (!param->primary) {
- vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
- INTEL_GVT_PCI_CLASS_VGA_OTHER;
- vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
- INTEL_GVT_PCI_CLASS_VGA_OTHER;
- }
-
- /* Show guest that there isn't any stolen memory.*/
- gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
- *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
-
- intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
- gvt_aperture_pa_base(gvt), true);
-
- vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
- | PCI_COMMAND_MEMORY
- | PCI_COMMAND_MASTER);
- /*
- * Clear the bar upper 32bit and let guest to assign the new value
- */
- memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
- memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
- memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
-
- for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) {
- vgpu->cfg_space.bar[i].size = pci_resource_len(
- gvt->dev_priv->drm.pdev, i * 2);
- vgpu->cfg_space.bar[i].tracked = false;
- }
-}
-
void populate_pvinfo_page(struct intel_vgpu *vgpu)
{
/* setup the ballooning information */
@@ -177,7 +104,7 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt)
if (low_avail / min_low == 0)
break;
gvt->types[i].low_gm_size = min_low;
- gvt->types[i].high_gm_size = 3 * gvt->types[i].low_gm_size;
+ gvt->types[i].high_gm_size = max((min_low<<3), MB_TO_BYTES(384U));
gvt->types[i].fence = 4;
gvt->types[i].max_instance = low_avail / min_low;
gvt->types[i].avail_instance = gvt->types[i].max_instance;
@@ -217,7 +144,7 @@ static void intel_gvt_update_vgpu_types(struct intel_gvt *gvt)
*/
low_gm_avail = MB_TO_BYTES(256) - HOST_LOW_GM_SIZE -
gvt->gm.vgpu_allocated_low_gm_size;
- high_gm_avail = MB_TO_BYTES(256) * 3 - HOST_HIGH_GM_SIZE -
+ high_gm_avail = MB_TO_BYTES(256) * 8UL - HOST_HIGH_GM_SIZE -
gvt->gm.vgpu_allocated_high_gm_size;
fence_avail = gvt_fence_sz(gvt) - HOST_FENCE -
gvt->fence.vgpu_allocated_fence_num;
@@ -268,7 +195,7 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu)
intel_vgpu_clean_gtt(vgpu);
intel_gvt_hypervisor_detach_vgpu(vgpu);
intel_vgpu_free_resource(vgpu);
- clean_vgpu_mmio(vgpu);
+ intel_vgpu_clean_mmio(vgpu);
vfree(vgpu);
intel_gvt_update_vgpu_types(gvt);
@@ -300,11 +227,11 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
vgpu->gvt = gvt;
bitmap_zero(vgpu->tlb_handle_pending, I915_NUM_ENGINES);
- setup_vgpu_cfg_space(vgpu, param);
+ intel_vgpu_init_cfg_space(vgpu, param->primary);
- ret = setup_vgpu_mmio(vgpu);
+ ret = intel_vgpu_init_mmio(vgpu);
if (ret)
- goto out_free_vgpu;
+ goto out_clean_idr;
ret = intel_vgpu_alloc_resource(vgpu, param);
if (ret)
@@ -354,7 +281,9 @@ out_detach_hypervisor_vgpu:
out_clean_vgpu_resource:
intel_vgpu_free_resource(vgpu);
out_clean_vgpu_mmio:
- clean_vgpu_mmio(vgpu);
+ intel_vgpu_clean_mmio(vgpu);
+out_clean_idr:
+ idr_remove(&gvt->vgpu_idr, vgpu->id);
out_free_vgpu:
vfree(vgpu);
mutex_unlock(&gvt->lock);
@@ -398,7 +327,75 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
}
/**
- * intel_gvt_reset_vgpu - reset a virtual GPU
+ * intel_gvt_reset_vgpu_locked - reset a virtual GPU by DMLR or GT reset
+ * @vgpu: virtual GPU
+ * @dmlr: vGPU Device Model Level Reset or GT Reset
+ * @engine_mask: engines to reset for GT reset
+ *
+ * This function is called when user wants to reset a virtual GPU through
+ * device model reset or GT reset. The caller should hold the gvt lock.
+ *
+ * vGPU Device Model Level Reset (DMLR) simulates the PCI level reset to reset
+ * the whole vGPU to default state as when it is created. This vGPU function
+ * is required both for functionary and security concerns.The ultimate goal
+ * of vGPU FLR is that reuse a vGPU instance by virtual machines. When we
+ * assign a vGPU to a virtual machine we must isse such reset first.
+ *
+ * Full GT Reset and Per-Engine GT Reset are soft reset flow for GPU engines
+ * (Render, Blitter, Video, Video Enhancement). It is defined by GPU Spec.
+ * Unlike the FLR, GT reset only reset particular resource of a vGPU per
+ * the reset request. Guest driver can issue a GT reset by programming the
+ * virtual GDRST register to reset specific virtual GPU engine or all
+ * engines.
+ *
+ * The parameter dev_level is to identify if we will do DMLR or GT reset.
+ * The parameter engine_mask is to specific the engines that need to be
+ * resetted. If value ALL_ENGINES is given for engine_mask, it means
+ * the caller requests a full GT reset that we will reset all virtual
+ * GPU engines. For FLR, engine_mask is ignored.
+ */
+void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
+ unsigned int engine_mask)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
+
+ gvt_dbg_core("------------------------------------------\n");
+ gvt_dbg_core("resseting vgpu%d, dmlr %d, engine_mask %08x\n",
+ vgpu->id, dmlr, engine_mask);
+ vgpu->resetting = true;
+
+ intel_vgpu_stop_schedule(vgpu);
+ /*
+ * The current_vgpu will set to NULL after stopping the
+ * scheduler when the reset is triggered by current vgpu.
+ */
+ if (scheduler->current_vgpu == NULL) {
+ mutex_unlock(&gvt->lock);
+ intel_gvt_wait_vgpu_idle(vgpu);
+ mutex_lock(&gvt->lock);
+ }
+
+ intel_vgpu_reset_execlist(vgpu, dmlr ? ALL_ENGINES : engine_mask);
+
+ /* full GPU reset or device model level reset */
+ if (engine_mask == ALL_ENGINES || dmlr) {
+ intel_vgpu_reset_gtt(vgpu, dmlr);
+ intel_vgpu_reset_resource(vgpu);
+ intel_vgpu_reset_mmio(vgpu);
+ populate_pvinfo_page(vgpu);
+
+ if (dmlr)
+ intel_vgpu_reset_cfg_space(vgpu);
+ }
+
+ vgpu->resetting = false;
+ gvt_dbg_core("reset vgpu%d done\n", vgpu->id);
+ gvt_dbg_core("------------------------------------------\n");
+}
+
+/**
+ * intel_gvt_reset_vgpu - reset a virtual GPU (Function Level)
* @vgpu: virtual GPU
*
* This function is called when user wants to reset a virtual GPU.
@@ -406,4 +403,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
*/
void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu)
{
+ mutex_lock(&vgpu->gvt->lock);
+ intel_gvt_reset_vgpu_locked(vgpu, true, 0);
+ mutex_unlock(&vgpu->gvt->lock);
}
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 9d7b5a8c8dea..fa69d72fdcb9 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -159,8 +159,35 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_printf(m, " (%sgtt offset: %08llx, size: %08llx",
i915_vma_is_ggtt(vma) ? "g" : "pp",
vma->node.start, vma->node.size);
- if (i915_vma_is_ggtt(vma))
- seq_printf(m, ", type: %u", vma->ggtt_view.type);
+ if (i915_vma_is_ggtt(vma)) {
+ switch (vma->ggtt_view.type) {
+ case I915_GGTT_VIEW_NORMAL:
+ seq_puts(m, ", normal");
+ break;
+
+ case I915_GGTT_VIEW_PARTIAL:
+ seq_printf(m, ", partial [%08llx+%x]",
+ vma->ggtt_view.partial.offset << PAGE_SHIFT,
+ vma->ggtt_view.partial.size << PAGE_SHIFT);
+ break;
+
+ case I915_GGTT_VIEW_ROTATED:
+ seq_printf(m, ", rotated [(%ux%u, stride=%u, offset=%u), (%ux%u, stride=%u, offset=%u)]",
+ vma->ggtt_view.rotated.plane[0].width,
+ vma->ggtt_view.rotated.plane[0].height,
+ vma->ggtt_view.rotated.plane[0].stride,
+ vma->ggtt_view.rotated.plane[0].offset,
+ vma->ggtt_view.rotated.plane[1].width,
+ vma->ggtt_view.rotated.plane[1].height,
+ vma->ggtt_view.rotated.plane[1].stride,
+ vma->ggtt_view.rotated.plane[1].offset);
+ break;
+
+ default:
+ MISSING_CASE(vma->ggtt_view.type);
+ break;
+ }
+ }
if (vma->fence)
seq_printf(m, " , fence: %d%s",
vma->fence->id,
@@ -2325,10 +2352,40 @@ static int i915_llc(struct seq_file *m, void *data)
return 0;
}
+static int i915_huc_load_status_info(struct seq_file *m, void *data)
+{
+ struct drm_i915_private *dev_priv = node_to_i915(m->private);
+ struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
+
+ if (!HAS_HUC_UCODE(dev_priv))
+ return 0;
+
+ seq_puts(m, "HuC firmware status:\n");
+ seq_printf(m, "\tpath: %s\n", huc_fw->path);
+ seq_printf(m, "\tfetch: %s\n",
+ intel_uc_fw_status_repr(huc_fw->fetch_status));
+ seq_printf(m, "\tload: %s\n",
+ intel_uc_fw_status_repr(huc_fw->load_status));
+ seq_printf(m, "\tversion wanted: %d.%d\n",
+ huc_fw->major_ver_wanted, huc_fw->minor_ver_wanted);
+ seq_printf(m, "\tversion found: %d.%d\n",
+ huc_fw->major_ver_found, huc_fw->minor_ver_found);
+ seq_printf(m, "\theader: offset is %d; size = %d\n",
+ huc_fw->header_offset, huc_fw->header_size);
+ seq_printf(m, "\tuCode: offset is %d; size = %d\n",
+ huc_fw->ucode_offset, huc_fw->ucode_size);
+ seq_printf(m, "\tRSA: offset is %d; size = %d\n",
+ huc_fw->rsa_offset, huc_fw->rsa_size);
+
+ seq_printf(m, "\nHuC status 0x%08x:\n", I915_READ(HUC_STATUS2));
+
+ return 0;
+}
+
static int i915_guc_load_status_info(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
u32 tmp, i;
if (!HAS_GUC_UCODE(dev_priv))
@@ -2336,15 +2393,15 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
seq_printf(m, "GuC firmware status:\n");
seq_printf(m, "\tpath: %s\n",
- guc_fw->guc_fw_path);
+ guc_fw->path);
seq_printf(m, "\tfetch: %s\n",
- intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
+ intel_uc_fw_status_repr(guc_fw->fetch_status));
seq_printf(m, "\tload: %s\n",
- intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ intel_uc_fw_status_repr(guc_fw->load_status));
seq_printf(m, "\tversion wanted: %d.%d\n",
- guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+ guc_fw->major_ver_wanted, guc_fw->minor_ver_wanted);
seq_printf(m, "\tversion found: %d.%d\n",
- guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found);
+ guc_fw->major_ver_found, guc_fw->minor_ver_found);
seq_printf(m, "\theader: offset is %d; size = %d\n",
guc_fw->header_offset, guc_fw->header_size);
seq_printf(m, "\tuCode: offset is %d; size = %d\n",
@@ -2532,6 +2589,29 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
i915_guc_log_control_get, i915_guc_log_control_set,
"%lld\n");
+static const char *psr2_live_status(u32 val)
+{
+ static const char * const live_status[] = {
+ "IDLE",
+ "CAPTURE",
+ "CAPTURE_FS",
+ "SLEEP",
+ "BUFON_FW",
+ "ML_UP",
+ "SU_STANDBY",
+ "FAST_SLEEP",
+ "DEEP_SLEEP",
+ "BUF_ON",
+ "TG_ON"
+ };
+
+ val = (val & EDP_PSR2_STATUS_STATE_MASK) >> EDP_PSR2_STATUS_STATE_SHIFT;
+ if (val < ARRAY_SIZE(live_status))
+ return live_status[val];
+
+ return "unknown";
+}
+
static int i915_edp_psr_status(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
@@ -2606,6 +2686,12 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
seq_printf(m, "Performance_Counter: %u\n", psrperf);
}
+ if (dev_priv->psr.psr2_support) {
+ u32 psr2 = I915_READ(EDP_PSR2_STATUS_CTL);
+
+ seq_printf(m, "EDP_PSR2_STATUS_CTL: %x [%s]\n",
+ psr2, psr2_live_status(psr2));
+ }
mutex_unlock(&dev_priv->psr.lock);
intel_runtime_pm_put(dev_priv);
@@ -4553,6 +4639,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_guc_info", i915_guc_info, 0},
{"i915_guc_load_status", i915_guc_load_status_info, 0},
{"i915_guc_log_dump", i915_guc_log_dump, 0},
+ {"i915_huc_load_status", i915_huc_load_status_info, 0},
{"i915_frequency_info", i915_frequency_info, 0},
{"i915_hangcheck_info", i915_hangcheck_info, 0},
{"i915_drpc_info", i915_drpc_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 4d22b4b479b8..4ae69ebe166e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -49,6 +49,7 @@
#include "i915_trace.h"
#include "i915_vgpu.h"
#include "intel_drv.h"
+#include "intel_uc.h"
static struct drm_driver driver;
@@ -315,6 +316,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_MIN_EU_IN_POOL:
value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool;
break;
+ case I915_PARAM_HUC_STATUS:
+ /* The register is already force-woken. We dont need
+ * any rpm here
+ */
+ value = I915_READ(HUC_STATUS2) & HUC_FW_VERIFIED;
+ break;
case I915_PARAM_MMAP_GTT_VERSION:
/* Though we've started our numbering from 1, and so class all
* earlier versions as 0, in effect their value is undefined as
@@ -599,6 +606,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret)
goto cleanup_irq;
+ intel_huc_init(dev_priv);
intel_guc_init(dev_priv);
ret = i915_gem_init(dev_priv);
@@ -627,6 +635,7 @@ cleanup_gem:
i915_gem_fini(dev_priv);
cleanup_irq:
intel_guc_fini(dev_priv);
+ intel_huc_fini(dev_priv);
drm_irq_uninstall(dev);
intel_teardown_gmbus(dev_priv);
cleanup_csr:
@@ -1114,7 +1123,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
/* Reveal our presence to userspace */
if (drm_dev_register(dev, 0) == 0) {
i915_debugfs_register(dev_priv);
- i915_guc_register(dev_priv);
+ i915_guc_log_register(dev_priv);
i915_setup_sysfs(dev_priv);
/* Depends on sysfs having been initialized */
@@ -1158,7 +1167,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
i915_perf_unregister(dev_priv);
i915_teardown_sysfs(dev_priv);
- i915_guc_unregister(dev_priv);
+ i915_guc_log_unregister(dev_priv);
i915_debugfs_unregister(dev_priv);
drm_dev_unregister(&dev_priv->drm);
@@ -1314,6 +1323,7 @@ void i915_driver_unload(struct drm_device *dev)
drain_workqueue(dev_priv->wq);
intel_guc_fini(dev_priv);
+ intel_huc_fini(dev_priv);
i915_gem_fini(dev_priv);
intel_fbc_cleanup_cfb(dev_priv);
@@ -1471,7 +1481,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
intel_display_set_init_power(dev_priv, false);
- fw_csr = !IS_BROXTON(dev_priv) &&
+ fw_csr = !IS_GEN9_LP(dev_priv) &&
suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload;
/*
* In case of firmware assisted context save/restore don't manually
@@ -1484,7 +1494,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
intel_power_domains_suspend(dev_priv);
ret = 0;
- if (IS_BROXTON(dev_priv))
+ if (IS_GEN9_LP(dev_priv))
bxt_enable_dc9(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_enable_pc8(dev_priv);
@@ -1692,7 +1702,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
intel_uncore_early_sanitize(dev_priv, true);
- if (IS_BROXTON(dev_priv)) {
+ if (IS_GEN9_LP(dev_priv)) {
if (!dev_priv->suspended_to_idle)
gen9_sanitize_dc_state(dev_priv);
bxt_disable_dc9(dev_priv);
@@ -1702,7 +1712,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
intel_uncore_sanitize(dev_priv);
- if (IS_BROXTON(dev_priv) ||
+ if (IS_GEN9_LP(dev_priv) ||
!(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload))
intel_power_domains_init_hw(dev_priv, true);
@@ -1728,25 +1738,9 @@ static int i915_resume_switcheroo(struct drm_device *dev)
return i915_drm_resume(dev);
}
-static void disable_engines_irq(struct drm_i915_private *dev_priv)
-{
- struct intel_engine_cs *engine;
- enum intel_engine_id id;
-
- /* Ensure irq handler finishes, and not run again. */
- disable_irq(dev_priv->drm.irq);
- for_each_engine(engine, dev_priv, id)
- tasklet_kill(&engine->irq_tasklet);
-}
-
-static void enable_engines_irq(struct drm_i915_private *dev_priv)
-{
- enable_irq(dev_priv->drm.irq);
-}
-
/**
* i915_reset - reset chip after a hang
- * @dev: drm device to reset
+ * @dev_priv: device private to reset
*
* Reset the chip. Useful if a hang is detected. Marks the device as wedged
* on failure.
@@ -1776,12 +1770,15 @@ void i915_reset(struct drm_i915_private *dev_priv)
error->reset_count++;
pr_notice("drm/i915: Resetting chip after gpu hang\n");
- i915_gem_reset_prepare(dev_priv);
+ disable_irq(dev_priv->drm.irq);
+ ret = i915_gem_reset_prepare(dev_priv);
+ if (ret) {
+ DRM_ERROR("GPU recovery failed\n");
+ intel_gpu_reset(dev_priv, ALL_ENGINES);
+ goto error;
+ }
- disable_engines_irq(dev_priv);
ret = intel_gpu_reset(dev_priv, ALL_ENGINES);
- enable_engines_irq(dev_priv);
-
if (ret) {
if (ret != -ENODEV)
DRM_ERROR("Failed to reset chip: %i\n", ret);
@@ -1816,6 +1813,7 @@ void i915_reset(struct drm_i915_private *dev_priv)
i915_queue_hangcheck(dev_priv);
wakeup:
+ enable_irq(dev_priv->drm.irq);
wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS);
return;
@@ -2326,7 +2324,7 @@ static int intel_runtime_suspend(struct device *kdev)
intel_runtime_pm_disable_interrupts(dev_priv);
ret = 0;
- if (IS_BROXTON(dev_priv)) {
+ if (IS_GEN9_LP(dev_priv)) {
bxt_display_core_uninit(dev_priv);
bxt_enable_dc9(dev_priv);
} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
@@ -2411,7 +2409,7 @@ static int intel_runtime_resume(struct device *kdev)
if (IS_GEN6(dev_priv))
intel_init_pch_refclk(dev_priv);
- if (IS_BROXTON(dev_priv)) {
+ if (IS_GEN9_LP(dev_priv)) {
bxt_disable_dc9(dev_priv);
bxt_display_core_init(dev_priv, true);
if (dev_priv->csr.dmc_payload &&
@@ -2549,8 +2547,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 52d01be956cc..244628065f94 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -49,6 +49,7 @@
#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
#include <drm/drm_gem.h>
#include <drm/drm_auth.h>
+#include <drm/drm_cache.h>
#include "i915_params.h"
#include "i915_reg.h"
@@ -78,8 +79,8 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20170109"
-#define DRIVER_TIMESTAMP 1483953121
+#define DRIVER_DATE "20170123"
+#define DRIVER_TIMESTAMP 1485156432
#undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */
@@ -1069,6 +1070,8 @@ struct intel_fbc {
struct work_struct underrun_work;
struct intel_fbc_state_cache {
+ struct i915_vma *vma;
+
struct {
unsigned int mode_flags;
uint32_t hsw_bdw_pixel_rate;
@@ -1082,15 +1085,14 @@ struct intel_fbc {
} plane;
struct {
- u64 ilk_ggtt_offset;
const struct drm_format_info *format;
unsigned int stride;
- int fence_reg;
- unsigned int tiling_mode;
} fb;
} state_cache;
struct intel_fbc_reg_params {
+ struct i915_vma *vma;
+
struct {
enum pipe pipe;
enum plane plane;
@@ -1098,10 +1100,8 @@ struct intel_fbc {
} crtc;
struct {
- u64 ggtt_offset;
const struct drm_format_info *format;
unsigned int stride;
- int fence_reg;
} fb;
int cfb_size;
@@ -1154,6 +1154,9 @@ struct i915_psr {
bool psr2_support;
bool aux_frame_sync;
bool link_standby;
+ bool y_cord_support;
+ bool colorimetry_support;
+ bool alpm;
};
enum intel_pch {
@@ -1809,6 +1812,7 @@ struct intel_pipe_crc {
enum intel_pipe_crc_source source;
int head, tail;
wait_queue_head_t wq;
+ int skipped;
};
struct i915_frontbuffer_tracking {
@@ -2069,6 +2073,7 @@ struct drm_i915_private {
struct intel_gvt *gvt;
+ struct intel_huc huc;
struct intel_guc guc;
struct intel_csr csr;
@@ -2843,6 +2848,7 @@ intel_info(const struct drm_i915_private *dev_priv)
#define HAS_GUC(dev_priv) ((dev_priv)->info.has_guc)
#define HAS_GUC_UCODE(dev_priv) (HAS_GUC(dev_priv))
#define HAS_GUC_SCHED(dev_priv) (HAS_GUC(dev_priv))
+#define HAS_HUC_UCODE(dev_priv) (HAS_GUC(dev_priv))
#define HAS_RESOURCE_STREAMER(dev_priv) ((dev_priv)->info.has_resource_streamer)
@@ -3101,10 +3107,10 @@ int i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-int i915_gem_set_tiling(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-int i915_gem_get_tiling(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
+int i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
void i915_gem_init_userptr(struct drm_i915_private *dev_priv);
int i915_gem_userptr_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
@@ -3323,7 +3329,7 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error)
return READ_ONCE(error->reset_count);
}
-void i915_gem_reset_prepare(struct drm_i915_private *dev_priv);
+int i915_gem_reset_prepare(struct drm_i915_private *dev_priv);
void i915_gem_reset_finish(struct drm_i915_private *dev_priv);
void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
void i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
@@ -3360,11 +3366,6 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
int i915_gem_open(struct drm_device *dev, struct drm_file *file);
void i915_gem_release(struct drm_device *dev, struct drm_file *file);
-u64 i915_gem_get_ggtt_size(struct drm_i915_private *dev_priv, u64 size,
- int tiling_mode);
-u64 i915_gem_get_ggtt_alignment(struct drm_i915_private *dev_priv, u64 size,
- int tiling_mode, bool fenced);
-
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
@@ -3374,36 +3375,12 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *gem_obj, int flags);
-struct i915_vma *
-i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view);
-
-struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view);
-
static inline struct i915_hw_ppgtt *
i915_vm_to_ppgtt(struct i915_address_space *vm)
{
return container_of(vm, struct i915_hw_ppgtt, base);
}
-static inline struct i915_vma *
-i915_gem_object_to_ggtt(struct drm_i915_gem_object *obj,
- const struct i915_ggtt_view *view)
-{
- return i915_gem_obj_to_vma(obj, &to_i915(obj->base.dev)->ggtt.base, view);
-}
-
-static inline unsigned long
-i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
- const struct i915_ggtt_view *view)
-{
- return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view));
-}
-
/* i915_gem_fence_reg.c */
int __must_check i915_vma_get_fence(struct i915_vma *vma);
int __must_check i915_vma_put_fence(struct i915_vma *vma);
@@ -3471,8 +3448,9 @@ int __must_check i915_gem_evict_something(struct i915_address_space *vm,
unsigned cache_level,
u64 start, u64 end,
unsigned flags);
-int __must_check i915_gem_evict_for_vma(struct i915_vma *vma,
- unsigned int flags);
+int __must_check i915_gem_evict_for_node(struct i915_address_space *vm,
+ struct drm_mm_node *node,
+ unsigned int flags);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
/* belongs in i915_gem_gtt.h */
@@ -3506,7 +3484,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
/* i915_gem_internal.c */
struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *dev_priv,
- unsigned int size);
+ phys_addr_t size);
/* i915_gem_shrinker.c */
unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
@@ -3531,6 +3509,11 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec
i915_gem_object_is_tiled(obj);
}
+u32 i915_gem_fence_size(struct drm_i915_private *dev_priv, u32 size,
+ unsigned int tiling, unsigned int stride);
+u32 i915_gem_fence_alignment(struct drm_i915_private *dev_priv, u32 size,
+ unsigned int tiling, unsigned int stride);
+
/* i915_debugfs.c */
#ifdef CONFIG_DEBUG_FS
int i915_debugfs_register(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index dc00d9ae6d92..a07b62732923 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1696,12 +1696,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
static unsigned int tile_row_pages(struct drm_i915_gem_object *obj)
{
- u64 size;
-
- size = i915_gem_object_get_stride(obj);
- size *= i915_gem_object_get_tiling(obj) == I915_TILING_Y ? 32 : 8;
-
- return size >> PAGE_SHIFT;
+ return i915_gem_object_get_tile_row_size(obj) >> PAGE_SHIFT;
}
/**
@@ -1754,6 +1749,29 @@ int i915_gem_mmap_gtt_version(void)
return 1;
}
+static inline struct i915_ggtt_view
+compute_partial_view(struct drm_i915_gem_object *obj,
+ pgoff_t page_offset,
+ unsigned int chunk)
+{
+ struct i915_ggtt_view view;
+
+ if (i915_gem_object_is_tiled(obj))
+ chunk = roundup(chunk, tile_row_pages(obj));
+
+ view.type = I915_GGTT_VIEW_PARTIAL;
+ view.partial.offset = rounddown(page_offset, chunk);
+ view.partial.size =
+ min_t(unsigned int, chunk,
+ (obj->base.size >> PAGE_SHIFT) - view.partial.offset);
+
+ /* If the partial covers the entire object, just create a normal VMA. */
+ if (chunk >= obj->base.size >> PAGE_SHIFT)
+ view.type = I915_GGTT_VIEW_NORMAL;
+
+ return view;
+}
+
/**
* i915_gem_fault - fault a page into the GTT
* @area: CPU VMA in question
@@ -1830,26 +1848,9 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
/* Now pin it into the GTT as needed */
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, flags);
if (IS_ERR(vma)) {
- struct i915_ggtt_view view;
- unsigned int chunk_size;
-
/* Use a partial view if it is bigger than available space */
- chunk_size = MIN_CHUNK_PAGES;
- if (i915_gem_object_is_tiled(obj))
- chunk_size = roundup(chunk_size, tile_row_pages(obj));
-
- memset(&view, 0, sizeof(view));
- view.type = I915_GGTT_VIEW_PARTIAL;
- view.params.partial.offset = rounddown(page_offset, chunk_size);
- view.params.partial.size =
- min_t(unsigned int, chunk_size,
- vma_pages(area) - view.params.partial.offset);
-
- /* If the partial covers the entire object, just create a
- * normal VMA.
- */
- if (chunk_size >= obj->base.size >> PAGE_SHIFT)
- view.type = I915_GGTT_VIEW_NORMAL;
+ struct i915_ggtt_view view =
+ compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
/* Userspace is now writing through an untracked VMA, abandon
* all hope that the hardware is able to track future writes.
@@ -1878,7 +1879,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
/* Finally, remap it using the new GTT offset */
ret = remap_io_mapping(area,
- area->vm_start + (vma->ggtt_view.params.partial.offset << PAGE_SHIFT),
+ area->vm_start + (vma->ggtt_view.partial.offset << PAGE_SHIFT),
(ggtt->mappable_base + vma->node.start) >> PAGE_SHIFT,
min_t(u64, vma->size, area->vm_end - area->vm_start),
&ggtt->mappable);
@@ -2021,69 +2022,6 @@ void i915_gem_runtime_suspend(struct drm_i915_private *dev_priv)
}
}
-/**
- * i915_gem_get_ggtt_size - return required global GTT size for an object
- * @dev_priv: i915 device
- * @size: object size
- * @tiling_mode: tiling mode
- *
- * Return the required global GTT size for an object, taking into account
- * potential fence register mapping.
- */
-u64 i915_gem_get_ggtt_size(struct drm_i915_private *dev_priv,
- u64 size, int tiling_mode)
-{
- u64 ggtt_size;
-
- GEM_BUG_ON(size == 0);
-
- if (INTEL_GEN(dev_priv) >= 4 ||
- tiling_mode == I915_TILING_NONE)
- return size;
-
- /* Previous chips need a power-of-two fence region when tiling */
- if (IS_GEN3(dev_priv))
- ggtt_size = 1024*1024;
- else
- ggtt_size = 512*1024;
-
- while (ggtt_size < size)
- ggtt_size <<= 1;
-
- return ggtt_size;
-}
-
-/**
- * i915_gem_get_ggtt_alignment - return required global GTT alignment
- * @dev_priv: i915 device
- * @size: object size
- * @tiling_mode: tiling mode
- * @fenced: is fenced alignment required or not
- *
- * Return the required global GTT alignment for an object, taking into account
- * potential fence register mapping.
- */
-u64 i915_gem_get_ggtt_alignment(struct drm_i915_private *dev_priv, u64 size,
- int tiling_mode, bool fenced)
-{
- GEM_BUG_ON(size == 0);
-
- /*
- * Minimum alignment is 4k (GTT page size), but might be greater
- * if a fence register is needed for the object.
- */
- if (INTEL_GEN(dev_priv) >= 4 ||
- (!fenced && (IS_G33(dev_priv) || IS_PINEVIEW(dev_priv))) ||
- tiling_mode == I915_TILING_NONE)
- return 4096;
-
- /*
- * Previous chips need to be aligned to the size of the smallest
- * fence register that can contain the object.
- */
- return i915_gem_get_ggtt_size(dev_priv, size, tiling_mode);
-}
-
static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
@@ -2666,13 +2604,52 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
if (__i915_gem_request_completed(request))
continue;
+ GEM_BUG_ON(request->engine != engine);
return request;
}
return NULL;
}
-static void reset_request(struct drm_i915_gem_request *request)
+static bool engine_stalled(struct intel_engine_cs *engine)
+{
+ if (!engine->hangcheck.stalled)
+ return false;
+
+ /* Check for possible seqno movement after hang declaration */
+ if (engine->hangcheck.seqno != intel_engine_get_seqno(engine)) {
+ DRM_DEBUG_DRIVER("%s pardoned\n", engine->name);
+ return false;
+ }
+
+ return true;
+}
+
+int i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
+{
+ struct intel_engine_cs *engine;
+ enum intel_engine_id id;
+ int err = 0;
+
+ /* Ensure irq handler finishes, and not run again. */
+ for_each_engine(engine, dev_priv, id) {
+ struct drm_i915_gem_request *request;
+
+ tasklet_kill(&engine->irq_tasklet);
+
+ if (engine_stalled(engine)) {
+ request = i915_gem_find_active_request(engine);
+ if (request && request->fence.error == -EIO)
+ err = -EIO; /* Previous reset failed! */
+ }
+ }
+
+ i915_gem_revoke_fences(dev_priv);
+
+ return err;
+}
+
+static void skip_request(struct drm_i915_gem_request *request)
{
void *vaddr = request->ring->vaddr;
u32 head;
@@ -2687,20 +2664,74 @@ static void reset_request(struct drm_i915_gem_request *request)
head = 0;
}
memset(vaddr + head, 0, request->postfix - head);
+
+ dma_fence_set_error(&request->fence, -EIO);
}
-void i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
+static void engine_skip_context(struct drm_i915_gem_request *request)
{
- i915_gem_revoke_fences(dev_priv);
+ struct intel_engine_cs *engine = request->engine;
+ struct i915_gem_context *hung_ctx = request->ctx;
+ struct intel_timeline *timeline;
+ unsigned long flags;
+
+ timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
+
+ spin_lock_irqsave(&engine->timeline->lock, flags);
+ spin_lock(&timeline->lock);
+
+ list_for_each_entry_continue(request, &engine->timeline->requests, link)
+ if (request->ctx == hung_ctx)
+ skip_request(request);
+
+ list_for_each_entry(request, &timeline->requests, link)
+ skip_request(request);
+
+ spin_unlock(&timeline->lock);
+ spin_unlock_irqrestore(&engine->timeline->lock, flags);
+}
+
+/* Returns true if the request was guilty of hang */
+static bool i915_gem_reset_request(struct drm_i915_gem_request *request)
+{
+ /* Read once and return the resolution */
+ const bool guilty = engine_stalled(request->engine);
+
+ /* The guilty request will get skipped on a hung engine.
+ *
+ * Users of client default contexts do not rely on logical
+ * state preserved between batches so it is safe to execute
+ * queued requests following the hang. Non default contexts
+ * rely on preserved state, so skipping a batch loses the
+ * evolution of the state and it needs to be considered corrupted.
+ * Executing more queued batches on top of corrupted state is
+ * risky. But we take the risk by trying to advance through
+ * the queued requests in order to make the client behaviour
+ * more predictable around resets, by not throwing away random
+ * amount of batches it has prepared for execution. Sophisticated
+ * clients can use gem_reset_stats_ioctl and dma fence status
+ * (exported via sync_file info ioctl on explicit fences) to observe
+ * when it loses the context state and should rebuild accordingly.
+ *
+ * The context ban, and ultimately the client ban, mechanism are safety
+ * valves if client submission ends up resulting in nothing more than
+ * subsequent hangs.
+ */
+
+ if (guilty) {
+ i915_gem_context_mark_guilty(request->ctx);
+ skip_request(request);
+ } else {
+ i915_gem_context_mark_innocent(request->ctx);
+ dma_fence_set_error(&request->fence, -EAGAIN);
+ }
+
+ return guilty;
}
static void i915_gem_reset_engine(struct intel_engine_cs *engine)
{
struct drm_i915_gem_request *request;
- struct i915_gem_context *hung_ctx;
- struct intel_timeline *timeline;
- unsigned long flags;
- bool ring_hung;
if (engine->irq_seqno_barrier)
engine->irq_seqno_barrier(engine);
@@ -2709,22 +2740,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
if (!request)
return;
- hung_ctx = request->ctx;
-
- ring_hung = engine->hangcheck.stalled;
- if (engine->hangcheck.seqno != intel_engine_get_seqno(engine)) {
- DRM_DEBUG_DRIVER("%s pardoned, was guilty? %s\n",
- engine->name,
- yesno(ring_hung));
- ring_hung = false;
- }
-
- if (ring_hung)
- i915_gem_context_mark_guilty(hung_ctx);
- else
- i915_gem_context_mark_innocent(hung_ctx);
-
- if (!ring_hung)
+ if (!i915_gem_reset_request(request))
return;
DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n",
@@ -2734,34 +2750,8 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
engine->reset_hw(engine, request);
/* If this context is now banned, skip all of its pending requests. */
- if (!i915_gem_context_is_banned(hung_ctx))
- return;
-
- /* Users of the default context do not rely on logical state
- * preserved between batches. They have to emit full state on
- * every batch and so it is safe to execute queued requests following
- * the hang.
- *
- * Other contexts preserve state, now corrupt. We want to skip all
- * queued requests that reference the corrupt context.
- */
- if (i915_gem_context_is_default(hung_ctx))
- return;
-
- timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
-
- spin_lock_irqsave(&engine->timeline->lock, flags);
- spin_lock(&timeline->lock);
-
- list_for_each_entry_continue(request, &engine->timeline->requests, link)
- if (request->ctx == hung_ctx)
- reset_request(request);
-
- list_for_each_entry(request, &timeline->requests, link)
- reset_request(request);
-
- spin_unlock(&timeline->lock);
- spin_unlock_irqrestore(&engine->timeline->lock, flags);
+ if (i915_gem_context_is_banned(request->ctx))
+ engine_skip_context(request);
}
void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
@@ -2788,12 +2778,16 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
static void nop_submit_request(struct drm_i915_gem_request *request)
{
+ dma_fence_set_error(&request->fence, -EIO);
i915_gem_request_submit(request);
intel_engine_init_global_seqno(request->engine, request->global_seqno);
}
-static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
+static void engine_set_wedged(struct intel_engine_cs *engine)
{
+ struct drm_i915_gem_request *request;
+ unsigned long flags;
+
/* We need to be sure that no thread is running the old callback as
* we install the nop handler (otherwise we would submit a request
* to hardware that will never complete). In order to prevent this
@@ -2802,6 +2796,12 @@ static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
*/
engine->submit_request = nop_submit_request;
+ /* Mark all executing requests as skipped */
+ spin_lock_irqsave(&engine->timeline->lock, flags);
+ list_for_each_entry(request, &engine->timeline->requests, link)
+ dma_fence_set_error(&request->fence, -EIO);
+ spin_unlock_irqrestore(&engine->timeline->lock, flags);
+
/* Mark all pending requests as complete so that any concurrent
* (lockless) lookup doesn't try and wait upon the request as we
* reset it.
@@ -2837,7 +2837,7 @@ static int __i915_gem_set_wedged_BKL(void *data)
enum intel_engine_id id;
for_each_engine(engine, i915, id)
- i915_gem_cleanup_engine(engine);
+ engine_set_wedged(engine);
return 0;
}
@@ -3397,7 +3397,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_caching *args = data;
struct drm_i915_gem_object *obj;
enum i915_cache_level level;
- int ret;
+ int ret = 0;
switch (args->caching) {
case I915_CACHING_NONE:
@@ -3422,20 +3422,29 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- ret = i915_mutex_lock_interruptible(dev);
+ obj = i915_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ if (obj->cache_level == level)
+ goto out;
+
+ ret = i915_gem_object_wait(obj,
+ I915_WAIT_INTERRUPTIBLE,
+ MAX_SCHEDULE_TIMEOUT,
+ to_rps_client(file));
if (ret)
- return ret;
+ goto out;
- obj = i915_gem_object_lookup(file, args->handle);
- if (!obj) {
- ret = -ENOENT;
- goto unlock;
- }
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ goto out;
ret = i915_gem_object_set_cache_level(obj, level);
- i915_gem_object_put(obj);
-unlock:
mutex_unlock(&dev->struct_mutex);
+
+out:
+ i915_gem_object_put(obj);
return ret;
}
@@ -3485,7 +3494,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
* try to preserve the existing ABI).
*/
vma = ERR_PTR(-ENOSPC);
- if (view->type == I915_GGTT_VIEW_NORMAL)
+ if (!view || view->type == I915_GGTT_VIEW_NORMAL)
vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
PIN_MAPPABLE | PIN_NONBLOCK);
if (IS_ERR(vma)) {
@@ -3544,11 +3553,10 @@ i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
return;
if (--vma->obj->pin_display == 0)
- vma->display_alignment = 0;
+ vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
/* Bump the LRU to try and avoid premature eviction whilst flipping */
- if (!i915_vma_is_active(vma))
- list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
+ i915_gem_object_bump_inactive_ggtt(vma->obj);
i915_vma_unpin(vma);
}
@@ -3679,8 +3687,8 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
lockdep_assert_held(&obj->base.dev->struct_mutex);
- vma = i915_gem_obj_lookup_or_create_vma(obj, vm, view);
- if (IS_ERR(vma))
+ vma = i915_vma_instance(obj, vm, view);
+ if (unlikely(IS_ERR(vma)))
return vma;
if (i915_vma_misplaced(vma, size, alignment, flags)) {
@@ -3689,10 +3697,6 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
return ERR_PTR(-ENOSPC);
if (flags & PIN_MAPPABLE) {
- u32 fence_size;
-
- fence_size = i915_gem_get_ggtt_size(dev_priv, vma->size,
- i915_gem_object_get_tiling(obj));
/* If the required space is larger than the available
* aperture, we will not able to find a slot for the
* object and unbinding the object now will be in
@@ -3700,7 +3704,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
* the object in and out of the Global GTT and
* waste a lot of cycles under the mutex.
*/
- if (fence_size > dev_priv->ggtt.mappable_end)
+ if (vma->fence_size > dev_priv->ggtt.mappable_end)
return ERR_PTR(-E2BIG);
/* If NONBLOCK is set the caller is optimistically
@@ -3719,7 +3723,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
* we could try to minimise harm to others.
*/
if (flags & PIN_NONBLOCK &&
- fence_size > dev_priv->ggtt.mappable_end / 2)
+ vma->fence_size > dev_priv->ggtt.mappable_end / 2)
return ERR_PTR(-ENOSPC);
}
@@ -4193,7 +4197,8 @@ static void assert_kernel_context_is_current(struct drm_i915_private *dev_priv)
enum intel_engine_id id;
for_each_engine(engine, dev_priv, id)
- GEM_BUG_ON(!i915_gem_context_is_kernel(engine->last_retired_context));
+ GEM_BUG_ON(engine->last_retired_context &&
+ !i915_gem_context_is_kernel(engine->last_retired_context));
}
int i915_gem_suspend(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 40a6939e3956..17f90c618208 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -97,7 +97,7 @@
* part. It should be safe to decrease this, but it's more future proof as is.
*/
#define GEN6_CONTEXT_ALIGN (64<<10)
-#define GEN7_CONTEXT_ALIGN 4096
+#define GEN7_CONTEXT_ALIGN I915_GTT_MIN_ALIGNMENT
static size_t get_context_alignment(struct drm_i915_private *dev_priv)
{
@@ -205,27 +205,6 @@ alloc_context_obj(struct drm_i915_private *dev_priv, u64 size)
return obj;
}
-static void i915_ppgtt_close(struct i915_address_space *vm)
-{
- struct list_head *phases[] = {
- &vm->active_list,
- &vm->inactive_list,
- &vm->unbound_list,
- NULL,
- }, **phase;
-
- GEM_BUG_ON(vm->closed);
- vm->closed = true;
-
- for (phase = phases; *phase; phase++) {
- struct i915_vma *vma, *vn;
-
- list_for_each_entry_safe(vma, vn, *phase, vm_link)
- if (!i915_vma_is_closed(vma))
- i915_vma_close(vma);
- }
-}
-
static void context_close(struct i915_gem_context *ctx)
{
i915_gem_context_set_closed(ctx);
@@ -290,7 +269,7 @@ __create_hw_context(struct drm_i915_private *dev_priv,
goto err_out;
}
- vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
if (IS_ERR(vma)) {
i915_gem_object_put(obj);
ret = PTR_ERR(vma);
@@ -341,7 +320,7 @@ __create_hw_context(struct drm_i915_private *dev_priv,
if (HAS_GUC(dev_priv) && i915.enable_guc_loading)
ctx->ggtt_offset_bias = GUC_WOPCM_TOP;
else
- ctx->ggtt_offset_bias = 4096;
+ ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
return ctx;
@@ -456,7 +435,8 @@ int i915_gem_context_init(struct drm_i915_private *dev_priv)
dev_priv->hw_context_size = 0;
} else if (HAS_HW_CONTEXTS(dev_priv)) {
dev_priv->hw_context_size =
- round_up(get_context_size(dev_priv), 4096);
+ round_up(get_context_size(dev_priv),
+ I915_GTT_PAGE_SIZE);
if (dev_priv->hw_context_size > (1<<20)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
dev_priv->hw_context_size);
@@ -897,6 +877,26 @@ int i915_switch_context(struct drm_i915_gem_request *req)
return do_rcs_switch(req);
}
+static bool engine_has_kernel_context(struct intel_engine_cs *engine)
+{
+ struct i915_gem_timeline *timeline;
+
+ list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
+ struct intel_timeline *tl;
+
+ if (timeline == &engine->i915->gt.global_timeline)
+ continue;
+
+ tl = &timeline->engine[engine->id];
+ if (i915_gem_active_peek(&tl->last_request,
+ &engine->i915->drm.struct_mutex))
+ return false;
+ }
+
+ return (!engine->last_retired_context ||
+ i915_gem_context_is_kernel(engine->last_retired_context));
+}
+
int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
@@ -905,10 +905,15 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
lockdep_assert_held(&dev_priv->drm.struct_mutex);
+ i915_gem_retire_requests(dev_priv);
+
for_each_engine(engine, dev_priv, id) {
struct drm_i915_gem_request *req;
int ret;
+ if (engine_has_kernel_context(engine))
+ continue;
+
req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
if (IS_ERR(req))
return PTR_ERR(req);
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 026ebc5a452a..a43e44e18042 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -231,7 +231,8 @@ found:
/**
* i915_gem_evict_for_vma - Evict vmas to make room for binding a new one
- * @target: address space and range to evict for
+ * @vm: address space to evict from
+ * @target: range (and color) to evict for
* @flags: additional flags to control the eviction algorithm
*
* This function will try to evict vmas that overlap the target node.
@@ -239,18 +240,20 @@ found:
* To clarify: This is for freeing up virtual address space, not for freeing
* memory in e.g. the shrinker.
*/
-int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
+int i915_gem_evict_for_node(struct i915_address_space *vm,
+ struct drm_mm_node *target,
+ unsigned int flags)
{
LIST_HEAD(eviction_list);
struct drm_mm_node *node;
- u64 start = target->node.start;
- u64 end = start + target->node.size;
+ u64 start = target->start;
+ u64 end = start + target->size;
struct i915_vma *vma, *next;
bool check_color;
int ret = 0;
- lockdep_assert_held(&target->vm->i915->drm.struct_mutex);
- trace_i915_gem_evict_vma(target, flags);
+ lockdep_assert_held(&vm->i915->drm.struct_mutex);
+ trace_i915_gem_evict_node(vm, target, flags);
/* Retire before we search the active list. Although we have
* reasonable accuracy in our retirement lists, we may have
@@ -258,18 +261,18 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
* retiring.
*/
if (!(flags & PIN_NONBLOCK))
- i915_gem_retire_requests(target->vm->i915);
+ i915_gem_retire_requests(vm->i915);
- check_color = target->vm->mm.color_adjust;
+ check_color = vm->mm.color_adjust;
if (check_color) {
/* Expand search to cover neighbouring guard pages (or lack!) */
- if (start > target->vm->start)
- start -= 4096;
- if (end < target->vm->start + target->vm->total)
- end += 4096;
+ if (start > vm->start)
+ start -= I915_GTT_PAGE_SIZE;
+ if (end < vm->start + vm->total)
+ end += I915_GTT_PAGE_SIZE;
}
- drm_mm_for_each_node_in_range(node, &target->vm->mm, start, end) {
+ drm_mm_for_each_node_in_range(node, &vm->mm, start, end) {
/* If we find any non-objects (!vma), we cannot evict them */
if (node->color == I915_COLOR_UNEVICTABLE) {
ret = -ENOSPC;
@@ -285,12 +288,12 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
* those as well to make room for our guard pages.
*/
if (check_color) {
- if (vma->node.start + vma->node.size == target->node.start) {
- if (vma->node.color == target->node.color)
+ if (vma->node.start + vma->node.size == node->start) {
+ if (vma->node.color == node->color)
continue;
}
- if (vma->node.start == target->node.start + target->node.size) {
- if (vma->node.color == target->node.color)
+ if (vma->node.start == node->start + node->size) {
+ if (vma->node.color == node->color)
continue;
}
}
@@ -302,7 +305,7 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
}
/* Overlap of objects in the same batch? */
- if (i915_vma_is_pinned(vma)) {
+ if (i915_vma_is_pinned(vma) || !list_empty(&vma->exec_list)) {
ret = -ENOSPC;
if (vma->exec_entry &&
vma->exec_entry->flags & EXEC_OBJECT_PINNED)
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index a5fe299da1d3..c66e90571031 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -184,7 +184,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
* from the (obj, vm) we don't run the risk of creating
* duplicated vmas for the same vm.
*/
- vma = i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
+ vma = i915_vma_instance(obj, vm, NULL);
if (unlikely(IS_ERR(vma))) {
DRM_DEBUG("Failed to lookup VMA\n");
ret = PTR_ERR(vma);
@@ -438,7 +438,7 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj,
memset(&cache->node, 0, sizeof(cache->node));
ret = drm_mm_insert_node_in_range_generic
(&ggtt->base.mm, &cache->node,
- 4096, 0, I915_COLOR_UNEVICTABLE,
+ PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE,
0, ggtt->mappable_end,
DRM_MM_SEARCH_DEFAULT,
DRM_MM_CREATE_DEFAULT);
@@ -851,8 +851,7 @@ eb_vma_misplaced(struct i915_vma *vma)
WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
!i915_vma_is_ggtt(vma));
- if (entry->alignment &&
- vma->node.start & (entry->alignment - 1))
+ if (entry->alignment && !IS_ALIGNED(vma->node.start, entry->alignment))
return true;
if (vma->node.size < entry->pad_to_size)
diff --git a/drivers/gpu/drm/i915/i915_gem_fence_reg.c b/drivers/gpu/drm/i915/i915_gem_fence_reg.c
index 775059e19ab9..fadbe8f4c745 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence_reg.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence_reg.c
@@ -77,16 +77,17 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *fence,
val = 0;
if (vma) {
- unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
- bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj);
- u32 row_size = stride * (is_y_tiled ? 32 : 8);
- u32 size = rounddown((u32)vma->node.size, row_size);
- val = ((vma->node.start + size - 4096) & 0xfffff000) << 32;
- val |= vma->node.start & 0xfffff000;
+ GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
+ GEM_BUG_ON(!IS_ALIGNED(vma->node.start, I965_FENCE_PAGE));
+ GEM_BUG_ON(!IS_ALIGNED(vma->fence_size, I965_FENCE_PAGE));
+ GEM_BUG_ON(!IS_ALIGNED(stride, 128));
+
+ val = (vma->node.start + vma->fence_size - I965_FENCE_PAGE) << 32;
+ val |= vma->node.start;
val |= (u64)((stride / 128) - 1) << fence_pitch_shift;
- if (is_y_tiled)
+ if (i915_gem_object_get_tiling(vma->obj) == I915_TILING_Y)
val |= BIT(I965_FENCE_TILING_Y_SHIFT);
val |= I965_FENCE_REG_VALID;
}
@@ -122,31 +123,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *fence,
unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj);
- int pitch_val;
- int tile_width;
- WARN((vma->node.start & ~I915_FENCE_START_MASK) ||
- !is_power_of_2(vma->node.size) ||
- (vma->node.start & (vma->node.size - 1)),
- "object 0x%08llx [fenceable? %d] not 1M or pot-size (0x%08llx) aligned\n",
- vma->node.start,
- i915_vma_is_map_and_fenceable(vma),
- vma->node.size);
+ GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
+ GEM_BUG_ON(vma->node.start & ~I915_FENCE_START_MASK);
+ GEM_BUG_ON(!is_power_of_2(vma->fence_size));
+ GEM_BUG_ON(!IS_ALIGNED(vma->node.start, vma->fence_size));
if (is_y_tiled && HAS_128_BYTE_Y_TILING(fence->i915))
- tile_width = 128;
+ stride /= 128;
else
- tile_width = 512;
-
- /* Note: pitch better be a power of two tile widths */
- pitch_val = stride / tile_width;
- pitch_val = ffs(pitch_val) - 1;
+ stride /= 512;
+ GEM_BUG_ON(!is_power_of_2(stride));
val = vma->node.start;
if (is_y_tiled)
val |= BIT(I830_FENCE_TILING_Y_SHIFT);
- val |= I915_FENCE_SIZE_BITS(vma->node.size);
- val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+ val |= I915_FENCE_SIZE_BITS(vma->fence_size);
+ val |= ilog2(stride) << I830_FENCE_PITCH_SHIFT;
+
val |= I830_FENCE_REG_VALID;
}
@@ -166,25 +160,19 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *fence,
val = 0;
if (vma) {
- unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
- bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj);
- u32 pitch_val;
- WARN((vma->node.start & ~I830_FENCE_START_MASK) ||
- !is_power_of_2(vma->node.size) ||
- (vma->node.start & (vma->node.size - 1)),
- "object 0x%08llx not 512K or pot-size 0x%08llx aligned\n",
- vma->node.start, vma->node.size);
-
- pitch_val = stride / 128;
- pitch_val = ffs(pitch_val) - 1;
+ GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
+ GEM_BUG_ON(vma->node.start & ~I830_FENCE_START_MASK);
+ GEM_BUG_ON(!is_power_of_2(vma->fence_size));
+ GEM_BUG_ON(!is_power_of_2(stride / 128));
+ GEM_BUG_ON(!IS_ALIGNED(vma->node.start, vma->fence_size));
val = vma->node.start;
- if (is_y_tiled)
+ if (i915_gem_object_get_tiling(vma->obj) == I915_TILING_Y)
val |= BIT(I830_FENCE_TILING_Y_SHIFT);
- val |= I830_FENCE_SIZE_BITS(vma->node.size);
- val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+ val |= I830_FENCE_SIZE_BITS(vma->fence_size);
+ val |= ilog2(stride / 128) << I830_FENCE_PITCH_SHIFT;
val |= I830_FENCE_REG_VALID;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_fence_reg.h b/drivers/gpu/drm/i915/i915_gem_fence_reg.h
index 22c4a2d01adf..99a31ded4dfd 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence_reg.h
+++ b/drivers/gpu/drm/i915/i915_gem_fence_reg.h
@@ -30,6 +30,8 @@
struct drm_i915_private;
struct i915_vma;
+#define I965_FENCE_PAGE 4096UL
+
struct drm_i915_fence_reg {
struct list_head link;
struct drm_i915_private *i915;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index f698006fe883..e808aad203d8 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -23,10 +23,14 @@
*
*/
+#include <linux/log2.h>
+#include <linux/random.h>
#include <linux/seq_file.h>
#include <linux/stop_machine.h>
+
#include <drm/drmP.h>
#include <drm/i915_drm.h>
+
#include "i915_drv.h"
#include "i915_vgpu.h"
#include "i915_trace.h"
@@ -99,12 +103,29 @@
static int
i915_get_ggtt_vma_pages(struct i915_vma *vma);
-const struct i915_ggtt_view i915_ggtt_view_normal = {
- .type = I915_GGTT_VIEW_NORMAL,
-};
-const struct i915_ggtt_view i915_ggtt_view_rotated = {
- .type = I915_GGTT_VIEW_ROTATED,
-};
+static void gen6_ggtt_invalidate(struct drm_i915_private *dev_priv)
+{
+ /* Note that as an uncached mmio write, this should flush the
+ * WCB of the writes into the GGTT before it triggers the invalidate.
+ */
+ I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
+}
+
+static void guc_ggtt_invalidate(struct drm_i915_private *dev_priv)
+{
+ gen6_ggtt_invalidate(dev_priv);
+ I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+}
+
+static void gmch_ggtt_invalidate(struct drm_i915_private *dev_priv)
+{
+ intel_gtt_chipset_flush();
+}
+
+static inline void i915_ggtt_invalidate(struct drm_i915_private *i915)
+{
+ i915->ggtt.invalidate(i915);
+}
int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
int enable_ppgtt)
@@ -329,7 +350,7 @@ static int __setup_page_dma(struct drm_i915_private *dev_priv,
return -ENOMEM;
p->daddr = dma_map_page(kdev,
- p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
+ p->page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (dma_mapping_error(kdev, p->daddr)) {
__free_page(p->page);
@@ -353,7 +374,7 @@ static void cleanup_page_dma(struct drm_i915_private *dev_priv,
if (WARN_ON(!p->page))
return;
- dma_unmap_page(&pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
+ dma_unmap_page(&pdev->dev, p->daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
__free_page(p->page);
memset(p, 0, sizeof(*p));
}
@@ -626,10 +647,10 @@ static void gen8_initialize_pml4(struct i915_address_space *vm,
}
static void
-gen8_setup_page_directory(struct i915_hw_ppgtt *ppgtt,
- struct i915_page_directory_pointer *pdp,
- struct i915_page_directory *pd,
- int index)
+gen8_setup_pdpe(struct i915_hw_ppgtt *ppgtt,
+ struct i915_page_directory_pointer *pdp,
+ struct i915_page_directory *pd,
+ int index)
{
gen8_ppgtt_pdpe_t *page_directorypo;
@@ -642,10 +663,10 @@ gen8_setup_page_directory(struct i915_hw_ppgtt *ppgtt,
}
static void
-gen8_setup_page_directory_pointer(struct i915_hw_ppgtt *ppgtt,
- struct i915_pml4 *pml4,
- struct i915_page_directory_pointer *pdp,
- int index)
+gen8_setup_pml4e(struct i915_hw_ppgtt *ppgtt,
+ struct i915_pml4 *pml4,
+ struct i915_page_directory_pointer *pdp,
+ int index)
{
gen8_ppgtt_pml4e_t *pagemap = kmap_px(pml4);
@@ -793,9 +814,6 @@ static bool gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
struct i915_page_directory *pd;
uint64_t pdpe;
- gen8_ppgtt_pdpe_t *pdpe_vaddr;
- gen8_ppgtt_pdpe_t scratch_pdpe =
- gen8_pdpe_encode(px_dma(vm->scratch_pd), I915_CACHE_LLC);
gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
if (WARN_ON(!pdp->page_directory[pdpe]))
@@ -803,11 +821,7 @@ static bool gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
if (gen8_ppgtt_clear_pd(vm, pd, start, length)) {
__clear_bit(pdpe, pdp->used_pdpes);
- if (USES_FULL_48BIT_PPGTT(dev_priv)) {
- pdpe_vaddr = kmap_px(pdp);
- pdpe_vaddr[pdpe] = scratch_pdpe;
- kunmap_px(ppgtt, pdpe_vaddr);
- }
+ gen8_setup_pdpe(ppgtt, pdp, vm->scratch_pd, pdpe);
free_pd(vm->i915, pd);
}
}
@@ -832,9 +846,6 @@ static void gen8_ppgtt_clear_pml4(struct i915_address_space *vm,
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
struct i915_page_directory_pointer *pdp;
uint64_t pml4e;
- gen8_ppgtt_pml4e_t *pml4e_vaddr;
- gen8_ppgtt_pml4e_t scratch_pml4e =
- gen8_pml4e_encode(px_dma(vm->scratch_pdp), I915_CACHE_LLC);
GEM_BUG_ON(!USES_FULL_48BIT_PPGTT(vm->i915));
@@ -844,9 +855,7 @@ static void gen8_ppgtt_clear_pml4(struct i915_address_space *vm,
if (gen8_ppgtt_clear_pdp(vm, pdp, start, length)) {
__clear_bit(pml4e, pml4->used_pml4es);
- pml4e_vaddr = kmap_px(pml4);
- pml4e_vaddr[pml4e] = scratch_pml4e;
- kunmap_px(ppgtt, pml4e_vaddr);
+ gen8_setup_pml4e(ppgtt, pml4, vm->scratch_pdp, pml4e);
free_pdp(vm->i915, pdp);
}
}
@@ -1366,7 +1375,7 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
kunmap_px(ppgtt, page_directory);
__set_bit(pdpe, pdp->used_pdpes);
- gen8_setup_page_directory(ppgtt, pdp, pd, pdpe);
+ gen8_setup_pdpe(ppgtt, pdp, pd, pdpe);
}
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
@@ -1425,7 +1434,7 @@ static int gen8_alloc_va_range_4lvl(struct i915_address_space *vm,
if (ret)
goto err_out;
- gen8_setup_page_directory_pointer(ppgtt, pml4, pdp, pml4e);
+ gen8_setup_pml4e(ppgtt, pml4, pdp, pml4e);
}
bitmap_or(pml4->used_pml4es, new_pdps, pml4->used_pml4es,
@@ -2044,7 +2053,6 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
struct i915_address_space *vm = &ppgtt->base;
struct drm_i915_private *dev_priv = ppgtt->base.i915;
struct i915_ggtt *ggtt = &dev_priv->ggtt;
- bool retried = false;
int ret;
/* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
@@ -2057,29 +2065,14 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
if (ret)
return ret;
-alloc:
- ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm, &ppgtt->node,
- GEN6_PD_SIZE, GEN6_PD_ALIGN,
- I915_COLOR_UNEVICTABLE,
- 0, ggtt->base.total,
- DRM_MM_TOPDOWN);
- if (ret == -ENOSPC && !retried) {
- ret = i915_gem_evict_something(&ggtt->base,
- GEN6_PD_SIZE, GEN6_PD_ALIGN,
- I915_COLOR_UNEVICTABLE,
- 0, ggtt->base.total,
- 0);
- if (ret)
- goto err_out;
-
- retried = true;
- goto alloc;
- }
-
+ ret = i915_gem_gtt_insert(&ggtt->base, &ppgtt->node,
+ GEN6_PD_SIZE, GEN6_PD_ALIGN,
+ I915_COLOR_UNEVICTABLE,
+ 0, ggtt->base.total,
+ PIN_HIGH);
if (ret)
goto err_out;
-
if (ppgtt->node.start < ggtt->mappable_end)
DRM_DEBUG("Forced to use aperture for PDEs\n");
@@ -2267,6 +2260,27 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
return ppgtt;
}
+void i915_ppgtt_close(struct i915_address_space *vm)
+{
+ struct list_head *phases[] = {
+ &vm->active_list,
+ &vm->inactive_list,
+ &vm->unbound_list,
+ NULL,
+ }, **phase;
+
+ GEM_BUG_ON(vm->closed);
+ vm->closed = true;
+
+ for (phase = phases; *phase; phase++) {
+ struct i915_vma *vma, *vn;
+
+ list_for_each_entry_safe(vma, vn, *phase, vm_link)
+ if (!i915_vma_is_closed(vma))
+ i915_vma_close(vma);
+ }
+}
+
void i915_ppgtt_release(struct kref *kref)
{
struct i915_hw_ppgtt *ppgtt =
@@ -2331,16 +2345,6 @@ void i915_check_and_clear_faults(struct drm_i915_private *dev_priv)
POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS]));
}
-static void i915_ggtt_flush(struct drm_i915_private *dev_priv)
-{
- if (INTEL_INFO(dev_priv)->gen < 6) {
- intel_gtt_chipset_flush();
- } else {
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
- }
-}
-
void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
{
struct i915_ggtt *ggtt = &dev_priv->ggtt;
@@ -2355,7 +2359,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
ggtt->base.clear_range(&ggtt->base, ggtt->base.start, ggtt->base.total);
- i915_ggtt_flush(dev_priv);
+ i915_ggtt_invalidate(dev_priv);
}
int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
@@ -2394,15 +2398,13 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm,
enum i915_cache_level level,
u32 unused)
{
- struct drm_i915_private *dev_priv = vm->i915;
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
gen8_pte_t __iomem *pte =
- (gen8_pte_t __iomem *)dev_priv->ggtt.gsm +
- (offset >> PAGE_SHIFT);
+ (gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
gen8_set_pte(pte, gen8_pte_encode(addr, level));
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
+ ggtt->invalidate(vm->i915);
}
static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
@@ -2410,7 +2412,6 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
uint64_t start,
enum i915_cache_level level, u32 unused)
{
- struct drm_i915_private *dev_priv = vm->i915;
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
struct sgt_iter sgt_iter;
gen8_pte_t __iomem *gtt_entries;
@@ -2439,8 +2440,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
* want to flush the TLBs only after we're certain all the PTE updates
* have finished.
*/
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
+ ggtt->invalidate(vm->i915);
}
struct insert_entries {
@@ -2475,15 +2475,13 @@ static void gen6_ggtt_insert_page(struct i915_address_space *vm,
enum i915_cache_level level,
u32 flags)
{
- struct drm_i915_private *dev_priv = vm->i915;
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
gen6_pte_t __iomem *pte =
- (gen6_pte_t __iomem *)dev_priv->ggtt.gsm +
- (offset >> PAGE_SHIFT);
+ (gen6_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
iowrite32(vm->pte_encode(addr, level, flags), pte);
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
+ ggtt->invalidate(vm->i915);
}
/*
@@ -2497,7 +2495,6 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
uint64_t start,
enum i915_cache_level level, u32 flags)
{
- struct drm_i915_private *dev_priv = vm->i915;
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
struct sgt_iter sgt_iter;
gen6_pte_t __iomem *gtt_entries;
@@ -2525,8 +2522,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
* want to flush the TLBs only after we're certain all the PTE updates
* have finished.
*/
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
+ ggtt->invalidate(vm->i915);
}
static void nop_clear_range(struct i915_address_space *vm,
@@ -2723,11 +2719,11 @@ static void i915_gtt_color_adjust(const struct drm_mm_node *node,
u64 *end)
{
if (node->color != color)
- *start += 4096;
+ *start += I915_GTT_PAGE_SIZE;
node = list_next_entry(node, node_list);
if (node->allocated && node->color != color)
- *end -= 4096;
+ *end -= I915_GTT_PAGE_SIZE;
}
int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
@@ -2754,7 +2750,7 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
/* Reserve a mappable slot for our lockless error capture */
ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm,
&ggtt->error_capture,
- 4096, 0,
+ PAGE_SIZE, 0,
I915_COLOR_UNEVICTABLE,
0, ggtt->mappable_end,
0, 0);
@@ -3086,6 +3082,8 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
if (IS_CHERRYVIEW(dev_priv))
ggtt->base.insert_entries = gen8_ggtt_insert_entries__BKL;
+ ggtt->invalidate = gen6_ggtt_invalidate;
+
return ggtt_probe_common(ggtt, size);
}
@@ -3123,6 +3121,8 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
ggtt->base.unbind_vma = ggtt_unbind_vma;
ggtt->base.cleanup = gen6_gmch_remove;
+ ggtt->invalidate = gen6_ggtt_invalidate;
+
if (HAS_EDRAM(dev_priv))
ggtt->base.pte_encode = iris_pte_encode;
else if (IS_HASWELL(dev_priv))
@@ -3166,6 +3166,8 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt)
ggtt->base.unbind_vma = ggtt_unbind_vma;
ggtt->base.cleanup = i915_gmch_remove;
+ ggtt->invalidate = gmch_ggtt_invalidate;
+
if (unlikely(ggtt->do_idle_maps))
DRM_INFO("applying Ironlake quirks for intel_iommu\n");
@@ -3284,6 +3286,16 @@ int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv)
return 0;
}
+void i915_ggtt_enable_guc(struct drm_i915_private *i915)
+{
+ i915->ggtt.invalidate = guc_ggtt_invalidate;
+}
+
+void i915_ggtt_disable_guc(struct drm_i915_private *i915)
+{
+ i915->ggtt.invalidate = gen6_ggtt_invalidate;
+}
+
void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
{
struct i915_ggtt *ggtt = &dev_priv->ggtt;
@@ -3347,52 +3359,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
}
}
- i915_ggtt_flush(dev_priv);
-}
-
-struct i915_vma *
-i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view)
-{
- struct rb_node *rb;
-
- rb = obj->vma_tree.rb_node;
- while (rb) {
- struct i915_vma *vma = rb_entry(rb, struct i915_vma, obj_node);
- long cmp;
-
- cmp = i915_vma_compare(vma, vm, view);
- if (cmp == 0)
- return vma;
-
- if (cmp < 0)
- rb = rb->rb_right;
- else
- rb = rb->rb_left;
- }
-
- return NULL;
-}
-
-struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view)
-{
- struct i915_vma *vma;
-
- lockdep_assert_held(&obj->base.dev->struct_mutex);
- GEM_BUG_ON(view && !i915_is_ggtt(vm));
-
- vma = i915_gem_obj_to_vma(obj, vm, view);
- if (!vma) {
- vma = i915_vma_create(obj, vm, view);
- GEM_BUG_ON(vma != i915_gem_obj_to_vma(obj, vm, view));
- }
-
- GEM_BUG_ON(i915_vma_is_closed(vma));
- return vma;
+ i915_ggtt_invalidate(dev_priv);
}
static struct scatterlist *
@@ -3492,7 +3459,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
{
struct sg_table *st;
struct scatterlist *sg, *iter;
- unsigned int count = view->params.partial.size;
+ unsigned int count = view->partial.size;
unsigned int offset;
int ret = -ENOMEM;
@@ -3504,9 +3471,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
if (ret)
goto err_sg_alloc;
- iter = i915_gem_object_get_sg(obj,
- view->params.partial.offset,
- &offset);
+ iter = i915_gem_object_get_sg(obj, view->partial.offset, &offset);
GEM_BUG_ON(!iter);
sg = st->sgl;
@@ -3558,7 +3523,8 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
vma->pages = vma->obj->mm.pages;
else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
vma->pages =
- intel_rotate_fb_obj_pages(&vma->ggtt_view.params.rotated, vma->obj);
+ intel_rotate_fb_obj_pages(&vma->ggtt_view.rotated,
+ vma->obj);
else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
else
@@ -3579,3 +3545,207 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
return ret;
}
+/**
+ * i915_gem_gtt_reserve - reserve a node in an address_space (GTT)
+ * @vm: the &struct i915_address_space
+ * @node: the &struct drm_mm_node (typically i915_vma.mode)
+ * @size: how much space to allocate inside the GTT,
+ * must be #I915_GTT_PAGE_SIZE aligned
+ * @offset: where to insert inside the GTT,
+ * must be #I915_GTT_MIN_ALIGNMENT aligned, and the node
+ * (@offset + @size) must fit within the address space
+ * @color: color to apply to node, if this node is not from a VMA,
+ * color must be #I915_COLOR_UNEVICTABLE
+ * @flags: control search and eviction behaviour
+ *
+ * i915_gem_gtt_reserve() tries to insert the @node at the exact @offset inside
+ * the address space (using @size and @color). If the @node does not fit, it
+ * tries to evict any overlapping nodes from the GTT, including any
+ * neighbouring nodes if the colors do not match (to ensure guard pages between
+ * differing domains). See i915_gem_evict_for_node() for the gory details
+ * on the eviction algorithm. #PIN_NONBLOCK may used to prevent waiting on
+ * evicting active overlapping objects, and any overlapping node that is pinned
+ * or marked as unevictable will also result in failure.
+ *
+ * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
+ * asked to wait for eviction and interrupted.
+ */
+int i915_gem_gtt_reserve(struct i915_address_space *vm,
+ struct drm_mm_node *node,
+ u64 size, u64 offset, unsigned long color,
+ unsigned int flags)
+{
+ int err;
+
+ GEM_BUG_ON(!size);
+ GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
+ GEM_BUG_ON(!IS_ALIGNED(offset, I915_GTT_MIN_ALIGNMENT));
+ GEM_BUG_ON(range_overflows(offset, size, vm->total));
+ GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
+ GEM_BUG_ON(drm_mm_node_allocated(node));
+
+ node->size = size;
+ node->start = offset;
+ node->color = color;
+
+ err = drm_mm_reserve_node(&vm->mm, node);
+ if (err != -ENOSPC)
+ return err;
+
+ err = i915_gem_evict_for_node(vm, node, flags);
+ if (err == 0)
+ err = drm_mm_reserve_node(&vm->mm, node);
+
+ return err;
+}
+
+static u64 random_offset(u64 start, u64 end, u64 len, u64 align)
+{
+ u64 range, addr;
+
+ GEM_BUG_ON(range_overflows(start, len, end));
+ GEM_BUG_ON(round_up(start, align) > round_down(end - len, align));
+
+ range = round_down(end - len, align) - round_up(start, align);
+ if (range) {
+ if (sizeof(unsigned long) == sizeof(u64)) {
+ addr = get_random_long();
+ } else {
+ addr = get_random_int();
+ if (range > U32_MAX) {
+ addr <<= 32;
+ addr |= get_random_int();
+ }
+ }
+ div64_u64_rem(addr, range, &addr);
+ start += addr;
+ }
+
+ return round_up(start, align);
+}
+
+/**
+ * i915_gem_gtt_insert - insert a node into an address_space (GTT)
+ * @vm: the &struct i915_address_space
+ * @node: the &struct drm_mm_node (typically i915_vma.node)
+ * @size: how much space to allocate inside the GTT,
+ * must be #I915_GTT_PAGE_SIZE aligned
+ * @alignment: required alignment of starting offset, may be 0 but
+ * if specified, this must be a power-of-two and at least
+ * #I915_GTT_MIN_ALIGNMENT
+ * @color: color to apply to node
+ * @start: start of any range restriction inside GTT (0 for all),
+ * must be #I915_GTT_PAGE_SIZE aligned
+ * @end: end of any range restriction inside GTT (U64_MAX for all),
+ * must be #I915_GTT_PAGE_SIZE aligned if not U64_MAX
+ * @flags: control search and eviction behaviour
+ *
+ * i915_gem_gtt_insert() first searches for an available hole into which
+ * is can insert the node. The hole address is aligned to @alignment and
+ * its @size must then fit entirely within the [@start, @end] bounds. The
+ * nodes on either side of the hole must match @color, or else a guard page
+ * will be inserted between the two nodes (or the node evicted). If no
+ * suitable hole is found, first a victim is randomly selected and tested
+ * for eviction, otherwise then the LRU list of objects within the GTT
+ * is scanned to find the first set of replacement nodes to create the hole.
+ * Those old overlapping nodes are evicted from the GTT (and so must be
+ * rebound before any future use). Any node that is currently pinned cannot
+ * be evicted (see i915_vma_pin()). Similar if the node's VMA is currently
+ * active and #PIN_NONBLOCK is specified, that node is also skipped when
+ * searching for an eviction candidate. See i915_gem_evict_something() for
+ * the gory details on the eviction algorithm.
+ *
+ * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
+ * asked to wait for eviction and interrupted.
+ */
+int i915_gem_gtt_insert(struct i915_address_space *vm,
+ struct drm_mm_node *node,
+ u64 size, u64 alignment, unsigned long color,
+ u64 start, u64 end, unsigned int flags)
+{
+ u32 search_flag, alloc_flag;
+ u64 offset;
+ int err;
+
+ lockdep_assert_held(&vm->i915->drm.struct_mutex);
+ GEM_BUG_ON(!size);
+ GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
+ GEM_BUG_ON(alignment && !is_power_of_2(alignment));
+ GEM_BUG_ON(alignment && !IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT));
+ GEM_BUG_ON(start >= end);
+ GEM_BUG_ON(start > 0 && !IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
+ GEM_BUG_ON(end < U64_MAX && !IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
+ GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
+ GEM_BUG_ON(drm_mm_node_allocated(node));
+
+ if (unlikely(range_overflows(start, size, end)))
+ return -ENOSPC;
+
+ if (unlikely(round_up(start, alignment) > round_down(end - size, alignment)))
+ return -ENOSPC;
+
+ if (flags & PIN_HIGH) {
+ search_flag = DRM_MM_SEARCH_BELOW;
+ alloc_flag = DRM_MM_CREATE_TOP;
+ } else {
+ search_flag = DRM_MM_SEARCH_DEFAULT;
+ alloc_flag = DRM_MM_CREATE_DEFAULT;
+ }
+
+ /* We only allocate in PAGE_SIZE/GTT_PAGE_SIZE (4096) chunks,
+ * so we know that we always have a minimum alignment of 4096.
+ * The drm_mm range manager is optimised to return results
+ * with zero alignment, so where possible use the optimal
+ * path.
+ */
+ BUILD_BUG_ON(I915_GTT_MIN_ALIGNMENT > I915_GTT_PAGE_SIZE);
+ if (alignment <= I915_GTT_MIN_ALIGNMENT)
+ alignment = 0;
+
+ err = drm_mm_insert_node_in_range_generic(&vm->mm, node,
+ size, alignment, color,
+ start, end,
+ search_flag, alloc_flag);
+ if (err != -ENOSPC)
+ return err;
+
+ /* No free space, pick a slot at random.
+ *
+ * There is a pathological case here using a GTT shared between
+ * mmap and GPU (i.e. ggtt/aliasing_ppgtt but not full-ppgtt):
+ *
+ * |<-- 256 MiB aperture -->||<-- 1792 MiB unmappable -->|
+ * (64k objects) (448k objects)
+ *
+ * Now imagine that the eviction LRU is ordered top-down (just because
+ * pathology meets real life), and that we need to evict an object to
+ * make room inside the aperture. The eviction scan then has to walk
+ * the 448k list before it finds one within range. And now imagine that
+ * it has to search for a new hole between every byte inside the memcpy,
+ * for several simultaneous clients.
+ *
+ * On a full-ppgtt system, if we have run out of available space, there
+ * will be lots and lots of objects in the eviction list! Again,
+ * searching that LRU list may be slow if we are also applying any
+ * range restrictions (e.g. restriction to low 4GiB) and so, for
+ * simplicity and similarilty between different GTT, try the single
+ * random replacement first.
+ */
+ offset = random_offset(start, end,
+ size, alignment ?: I915_GTT_MIN_ALIGNMENT);
+ err = i915_gem_gtt_reserve(vm, node, size, offset, color, flags);
+ if (err != -ENOSPC)
+ return err;
+
+ /* Randomly selected placement is pinned, do a search */
+ err = i915_gem_evict_something(vm, size, alignment, color,
+ start, end, flags);
+ if (err)
+ return err;
+
+ search_flag = DRM_MM_SEARCH_DEFAULT;
+ return drm_mm_insert_node_in_range_generic(&vm->mm, node,
+ size, alignment, color,
+ start, end,
+ search_flag, alloc_flag);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 9e91d7e6149c..3c5ef5358cef 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -40,6 +40,9 @@
#include "i915_gem_timeline.h"
#include "i915_gem_request.h"
+#define I915_GTT_PAGE_SIZE 4096UL
+#define I915_GTT_MIN_ALIGNMENT I915_GTT_PAGE_SIZE
+
#define I915_FENCE_REG_NONE -1
#define I915_MAX_NUM_FENCES 32
/* 32 fences + sign bit for FENCE_REG_NONE */
@@ -142,34 +145,57 @@ typedef uint64_t gen8_ppgtt_pml4e_t;
struct sg_table;
-enum i915_ggtt_view_type {
- I915_GGTT_VIEW_NORMAL = 0,
- I915_GGTT_VIEW_ROTATED,
- I915_GGTT_VIEW_PARTIAL,
-};
-
struct intel_rotation_info {
- struct {
+ struct intel_rotation_plane_info {
/* tiles */
unsigned int width, height, stride, offset;
} plane[2];
+} __packed;
+
+static inline void assert_intel_rotation_info_is_packed(void)
+{
+ BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 8*sizeof(unsigned int));
+}
+
+struct intel_partial_info {
+ u64 offset;
+ unsigned int size;
+} __packed;
+
+static inline void assert_intel_partial_info_is_packed(void)
+{
+ BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int));
+}
+
+enum i915_ggtt_view_type {
+ I915_GGTT_VIEW_NORMAL = 0,
+ I915_GGTT_VIEW_ROTATED = sizeof(struct intel_rotation_info),
+ I915_GGTT_VIEW_PARTIAL = sizeof(struct intel_partial_info),
};
+static inline void assert_i915_ggtt_view_type_is_unique(void)
+{
+ /* As we encode the size of each branch inside the union into its type,
+ * we have to be careful that each branch has a unique size.
+ */
+ switch ((enum i915_ggtt_view_type)0) {
+ case I915_GGTT_VIEW_NORMAL:
+ case I915_GGTT_VIEW_PARTIAL:
+ case I915_GGTT_VIEW_ROTATED:
+ /* gcc complains if these are identical cases */
+ break;
+ }
+}
+
struct i915_ggtt_view {
enum i915_ggtt_view_type type;
-
union {
- struct {
- u64 offset;
- unsigned int size;
- } partial;
+ /* Members need to contain no holes/padding */
+ struct intel_partial_info partial;
struct intel_rotation_info rotated;
- } params;
+ };
};
-extern const struct i915_ggtt_view i915_ggtt_view_normal;
-extern const struct i915_ggtt_view i915_ggtt_view_rotated;
-
enum i915_cache_level;
struct i915_vma;
@@ -333,6 +359,7 @@ struct i915_ggtt {
/** "Graphics Stolen Memory" holds the global PTEs */
void __iomem *gsm;
+ void (*invalidate)(struct drm_i915_private *dev_priv);
bool do_idle_maps;
@@ -501,6 +528,8 @@ i915_vm_to_ggtt(struct i915_address_space *vm)
int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv);
int i915_ggtt_init_hw(struct drm_i915_private *dev_priv);
int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv);
+void i915_ggtt_enable_guc(struct drm_i915_private *i915);
+void i915_ggtt_disable_guc(struct drm_i915_private *i915);
int i915_gem_init_ggtt(struct drm_i915_private *dev_priv);
void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv);
@@ -509,6 +538,7 @@ void i915_ppgtt_release(struct kref *kref);
struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv,
struct drm_i915_file_private *fpriv,
const char *name);
+void i915_ppgtt_close(struct i915_address_space *vm);
static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
{
if (ppgtt)
@@ -529,6 +559,16 @@ int __must_check i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages);
+int i915_gem_gtt_reserve(struct i915_address_space *vm,
+ struct drm_mm_node *node,
+ u64 size, u64 offset, unsigned long color,
+ unsigned int flags);
+
+int i915_gem_gtt_insert(struct i915_address_space *vm,
+ struct drm_mm_node *node,
+ u64 size, u64 alignment, unsigned long color,
+ u64 start, u64 end, unsigned int flags);
+
/* Flags used by pin/bind&friends. */
#define PIN_NONBLOCK BIT(0)
#define PIN_MAPPABLE BIT(1)
@@ -543,6 +583,6 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
#define PIN_HIGH BIT(9)
#define PIN_OFFSET_BIAS BIT(10)
#define PIN_OFFSET_FIXED BIT(11)
-#define PIN_OFFSET_MASK (~4095)
+#define PIN_OFFSET_MASK (-I915_GTT_PAGE_SIZE)
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c
index 2222863e505f..17ce53d0d092 100644
--- a/drivers/gpu/drm/i915/i915_gem_internal.c
+++ b/drivers/gpu/drm/i915/i915_gem_internal.c
@@ -151,10 +151,16 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = {
*/
struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *i915,
- unsigned int size)
+ phys_addr_t size)
{
struct drm_i915_gem_object *obj;
+ GEM_BUG_ON(!size);
+ GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
+
+ if (overflows_type(size, obj->base.size))
+ return ERR_PTR(-E2BIG);
+
obj = i915_gem_object_alloc(i915);
if (!obj)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h
index 6a368de9d81e..290eaa7fc9eb 100644
--- a/drivers/gpu/drm/i915/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/i915_gem_object.h
@@ -317,6 +317,29 @@ i915_gem_object_get_stride(struct drm_i915_gem_object *obj)
return obj->tiling_and_stride & STRIDE_MASK;
}
+static inline unsigned int
+i915_gem_tile_height(unsigned int tiling)
+{
+ GEM_BUG_ON(!tiling);
+ return tiling == I915_TILING_Y ? 32 : 8;
+}
+
+static inline unsigned int
+i915_gem_object_get_tile_height(struct drm_i915_gem_object *obj)
+{
+ return i915_gem_tile_height(i915_gem_object_get_tiling(obj));
+}
+
+static inline unsigned int
+i915_gem_object_get_tile_row_size(struct drm_i915_gem_object *obj)
+{
+ return (i915_gem_object_get_stride(obj) *
+ i915_gem_object_get_tile_height(obj));
+}
+
+int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
+ unsigned int tiling, unsigned int stride);
+
static inline struct intel_engine_cs *
i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj)
{
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c
index 5af19b0bf713..b42c81b42487 100644
--- a/drivers/gpu/drm/i915/i915_gem_render_state.c
+++ b/drivers/gpu/drm/i915/i915_gem_render_state.c
@@ -187,20 +187,20 @@ int i915_gem_render_state_init(struct intel_engine_cs *engine)
if (!rodata)
return 0;
- if (rodata->batch_items * 4 > 4096)
+ if (rodata->batch_items * 4 > PAGE_SIZE)
return -EINVAL;
so = kmalloc(sizeof(*so), GFP_KERNEL);
if (!so)
return -ENOMEM;
- obj = i915_gem_object_create_internal(engine->i915, 4096);
+ obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
if (IS_ERR(obj)) {
ret = PTR_ERR(obj);
goto err_free;
}
- so->vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+ so->vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
if (IS_ERR(so->vma)) {
ret = PTR_ERR(so->vma);
goto err_obj;
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index 99056b948eda..72b7f7d9461d 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -307,26 +307,6 @@ void i915_gem_request_retire_upto(struct drm_i915_gem_request *req)
} while (tmp != req);
}
-static int i915_gem_check_wedge(struct drm_i915_private *dev_priv)
-{
- struct i915_gpu_error *error = &dev_priv->gpu_error;
-
- if (i915_terminally_wedged(error))
- return -EIO;
-
- if (i915_reset_in_progress(error)) {
- /* Non-interruptible callers can't handle -EAGAIN, hence return
- * -EIO unconditionally for these.
- */
- if (!dev_priv->mm.interruptible)
- return -EIO;
-
- return -EAGAIN;
- }
-
- return 0;
-}
-
static int i915_gem_init_global_seqno(struct drm_i915_private *i915, u32 seqno)
{
struct i915_gem_timeline *timeline = &i915->gt.global_timeline;
@@ -521,12 +501,10 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
lockdep_assert_held(&dev_priv->drm.struct_mutex);
/* ABI: Before userspace accesses the GPU (e.g. execbuffer), report
- * EIO if the GPU is already wedged, or EAGAIN to drop the struct_mutex
- * and restart.
+ * EIO if the GPU is already wedged.
*/
- ret = i915_gem_check_wedge(dev_priv);
- if (ret)
- return ERR_PTR(ret);
+ if (i915_terminally_wedged(&dev_priv->gpu_error))
+ return ERR_PTR(-EIO);
/* Pinning the contexts may generate requests in order to acquire
* GGTT space, so do this first before we reserve a seqno for
@@ -851,6 +829,13 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
lockdep_assert_held(&request->i915->drm.struct_mutex);
trace_i915_gem_request_add(request);
+ /* Make sure that no request gazumped us - if it was allocated after
+ * our i915_gem_request_alloc() and called __i915_add_request() before
+ * us, the timeline will hold its seqno which is later than ours.
+ */
+ GEM_BUG_ON(i915_seqno_passed(timeline->last_submitted_seqno,
+ request->fence.seqno));
+
/*
* To ensure that this call will not fail, space for its emissions
* should already have been reserved in the ring buffer. Let the ring
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index f1a1d33febcd..127d698e7c84 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -647,8 +647,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
stolen_offset, gtt_offset, size);
/* KISS and expect everything to be page-aligned */
- if (WARN_ON(size == 0) || WARN_ON(size & 4095) ||
- WARN_ON(stolen_offset & 4095))
+ if (WARN_ON(size == 0) ||
+ WARN_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)) ||
+ WARN_ON(!IS_ALIGNED(stolen_offset, I915_GTT_MIN_ALIGNMENT)))
return NULL;
stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
@@ -682,7 +683,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
if (ret)
goto err;
- vma = i915_gem_obj_lookup_or_create_vma(obj, &ggtt->base, NULL);
+ vma = i915_vma_instance(obj, &ggtt->base, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto err_pages;
@@ -693,15 +694,16 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
* setting up the GTT space. The actual reservation will occur
* later.
*/
- vma->node.start = gtt_offset;
- vma->node.size = size;
-
- ret = drm_mm_reserve_node(&ggtt->base.mm, &vma->node);
+ ret = i915_gem_gtt_reserve(&ggtt->base, &vma->node,
+ size, gtt_offset, obj->cache_level,
+ 0);
if (ret) {
DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
goto err_pages;
}
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+
vma->pages = obj->mm.pages;
vma->flags |= I915_VMA_GLOBAL_BIND;
__i915_vma_set_map_and_fenceable(vma);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 62ad375de6ca..b1361cfd4c5c 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -34,8 +34,8 @@
/**
* DOC: buffer object tiling
*
- * i915_gem_set_tiling() and i915_gem_get_tiling() is the userspace interface to
- * declare fence register requirements.
+ * i915_gem_set_tiling_ioctl() and i915_gem_get_tiling_ioctl() is the userspace
+ * interface to declare fence register requirements.
*
* In principle GEM doesn't care at all about the internal data layout of an
* object, and hence it also doesn't care about tiling or swizzling. There's two
@@ -58,86 +58,147 @@
* invovlement.
*/
+/**
+ * i915_gem_fence_size - required global GTT size for a fence
+ * @i915: i915 device
+ * @size: object size
+ * @tiling: tiling mode
+ * @stride: tiling stride
+ *
+ * Return the required global GTT size for a fence (view of a tiled object),
+ * taking into account potential fence register mapping.
+ */
+u32 i915_gem_fence_size(struct drm_i915_private *i915,
+ u32 size, unsigned int tiling, unsigned int stride)
+{
+ u32 ggtt_size;
+
+ GEM_BUG_ON(!size);
+
+ if (tiling == I915_TILING_NONE)
+ return size;
+
+ GEM_BUG_ON(!stride);
+
+ if (INTEL_GEN(i915) >= 4) {
+ stride *= i915_gem_tile_height(tiling);
+ GEM_BUG_ON(!IS_ALIGNED(stride, I965_FENCE_PAGE));
+ return roundup(size, stride);
+ }
+
+ /* Previous chips need a power-of-two fence region when tiling */
+ if (IS_GEN3(i915))
+ ggtt_size = 1024*1024;
+ else
+ ggtt_size = 512*1024;
+
+ while (ggtt_size < size)
+ ggtt_size <<= 1;
+
+ return ggtt_size;
+}
+
+/**
+ * i915_gem_fence_alignment - required global GTT alignment for a fence
+ * @i915: i915 device
+ * @size: object size
+ * @tiling: tiling mode
+ * @stride: tiling stride
+ *
+ * Return the required global GTT alignment for a fence (a view of a tiled
+ * object), taking into account potential fence register mapping.
+ */
+u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size,
+ unsigned int tiling, unsigned int stride)
+{
+ GEM_BUG_ON(!size);
+
+ /*
+ * Minimum alignment is 4k (GTT page size), but might be greater
+ * if a fence register is needed for the object.
+ */
+ if (tiling == I915_TILING_NONE)
+ return I915_GTT_MIN_ALIGNMENT;
+
+ if (INTEL_GEN(i915) >= 4)
+ return I965_FENCE_PAGE;
+
+ /*
+ * Previous chips need to be aligned to the size of the smallest
+ * fence register that can contain the object.
+ */
+ return i915_gem_fence_size(i915, size, tiling, stride);
+}
+
/* Check pitch constriants for all chips & tiling formats */
static bool
-i915_tiling_ok(struct drm_i915_private *dev_priv,
- int stride, int size, int tiling_mode)
+i915_tiling_ok(struct drm_i915_gem_object *obj,
+ unsigned int tiling, unsigned int stride)
{
- int tile_width;
+ struct drm_i915_private *i915 = to_i915(obj->base.dev);
+ unsigned int tile_width;
/* Linear is always fine */
- if (tiling_mode == I915_TILING_NONE)
+ if (tiling == I915_TILING_NONE)
return true;
- if (tiling_mode > I915_TILING_LAST)
+ if (tiling > I915_TILING_LAST)
return false;
- if (IS_GEN2(dev_priv) ||
- (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev_priv)))
- tile_width = 128;
- else
- tile_width = 512;
-
/* check maximum stride & object size */
/* i965+ stores the end address of the gtt mapping in the fence
* reg, so dont bother to check the size */
- if (INTEL_GEN(dev_priv) >= 7) {
+ if (INTEL_GEN(i915) >= 7) {
if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL)
return false;
- } else if (INTEL_GEN(dev_priv) >= 4) {
+ } else if (INTEL_GEN(i915) >= 4) {
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return false;
} else {
if (stride > 8192)
return false;
- if (IS_GEN3(dev_priv)) {
- if (size > I830_FENCE_MAX_SIZE_VAL << 20)
+ if (IS_GEN3(i915)) {
+ if (obj->base.size > I830_FENCE_MAX_SIZE_VAL << 20)
return false;
} else {
- if (size > I830_FENCE_MAX_SIZE_VAL << 19)
+ if (obj->base.size > I830_FENCE_MAX_SIZE_VAL << 19)
return false;
}
}
- if (stride < tile_width)
+ if (IS_GEN2(i915) ||
+ (tiling == I915_TILING_Y && HAS_128_BYTE_Y_TILING(i915)))
+ tile_width = 128;
+ else
+ tile_width = 512;
+
+ if (!IS_ALIGNED(stride, tile_width))
return false;
/* 965+ just needs multiples of tile width */
- if (INTEL_GEN(dev_priv) >= 4) {
- if (stride & (tile_width - 1))
- return false;
+ if (INTEL_GEN(i915) >= 4)
return true;
- }
/* Pre-965 needs power of two tile widths */
- if (stride & (stride - 1))
- return false;
-
- return true;
+ return is_power_of_2(stride);
}
-static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode)
+static bool i915_vma_fence_prepare(struct i915_vma *vma,
+ int tiling_mode, unsigned int stride)
{
- struct drm_i915_private *dev_priv = vma->vm->i915;
- u32 size;
+ struct drm_i915_private *i915 = vma->vm->i915;
+ u32 size, alignment;
if (!i915_vma_is_map_and_fenceable(vma))
return true;
- if (INTEL_GEN(dev_priv) == 3) {
- if (vma->node.start & ~I915_FENCE_START_MASK)
- return false;
- } else {
- if (vma->node.start & ~I830_FENCE_START_MASK)
- return false;
- }
-
- size = i915_gem_get_ggtt_size(dev_priv, vma->size, tiling_mode);
+ size = i915_gem_fence_size(i915, vma->size, tiling_mode, stride);
if (vma->node.size < size)
return false;
- if (vma->node.start & (size - 1))
+ alignment = i915_gem_fence_alignment(i915, vma->size, tiling_mode, stride);
+ if (!IS_ALIGNED(vma->node.start, alignment))
return false;
return true;
@@ -145,20 +206,20 @@ static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode)
/* Make the current GTT allocation valid for the change in tiling. */
static int
-i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode)
+i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj,
+ int tiling_mode, unsigned int stride)
{
- struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
struct i915_vma *vma;
int ret;
if (tiling_mode == I915_TILING_NONE)
return 0;
- if (INTEL_GEN(dev_priv) >= 4)
- return 0;
-
list_for_each_entry(vma, &obj->vma_list, obj_link) {
- if (i915_vma_fence_prepare(vma, tiling_mode))
+ if (!i915_vma_is_ggtt(vma))
+ break;
+
+ if (i915_vma_fence_prepare(vma, tiling_mode, stride))
continue;
ret = i915_vma_unbind(vma);
@@ -169,8 +230,100 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode)
return 0;
}
+int
+i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
+ unsigned int tiling, unsigned int stride)
+{
+ struct drm_i915_private *i915 = to_i915(obj->base.dev);
+ struct i915_vma *vma;
+ int err;
+
+ /* Make sure we don't cross-contaminate obj->tiling_and_stride */
+ BUILD_BUG_ON(I915_TILING_LAST & STRIDE_MASK);
+
+ GEM_BUG_ON(!i915_tiling_ok(obj, tiling, stride));
+ GEM_BUG_ON(!stride ^ (tiling == I915_TILING_NONE));
+ lockdep_assert_held(&i915->drm.struct_mutex);
+
+ if ((tiling | stride) == obj->tiling_and_stride)
+ return 0;
+
+ if (obj->framebuffer_references)
+ return -EBUSY;
+
+ /* We need to rebind the object if its current allocation
+ * no longer meets the alignment restrictions for its new
+ * tiling mode. Otherwise we can just leave it alone, but
+ * need to ensure that any fence register is updated before
+ * the next fenced (either through the GTT or by the BLT unit
+ * on older GPUs) access.
+ *
+ * After updating the tiling parameters, we then flag whether
+ * we need to update an associated fence register. Note this
+ * has to also include the unfenced register the GPU uses
+ * whilst executing a fenced command for an untiled object.
+ */
+
+ err = i915_gem_object_fence_prepare(obj, tiling, stride);
+ if (err)
+ return err;
+
+ /* If the memory has unknown (i.e. varying) swizzling, we pin the
+ * pages to prevent them being swapped out and causing corruption
+ * due to the change in swizzling.
+ */
+ mutex_lock(&obj->mm.lock);
+ if (obj->mm.pages &&
+ obj->mm.madv == I915_MADV_WILLNEED &&
+ i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
+ if (tiling == I915_TILING_NONE) {
+ GEM_BUG_ON(!obj->mm.quirked);
+ __i915_gem_object_unpin_pages(obj);
+ obj->mm.quirked = false;
+ }
+ if (!i915_gem_object_is_tiled(obj)) {
+ GEM_BUG_ON(!obj->mm.quirked);
+ __i915_gem_object_pin_pages(obj);
+ obj->mm.quirked = true;
+ }
+ }
+ mutex_unlock(&obj->mm.lock);
+
+ list_for_each_entry(vma, &obj->vma_list, obj_link) {
+ if (!i915_vma_is_ggtt(vma))
+ break;
+
+ vma->fence_size =
+ i915_gem_fence_size(i915, vma->size, tiling, stride);
+ vma->fence_alignment =
+ i915_gem_fence_alignment(i915,
+ vma->size, tiling, stride);
+
+ if (vma->fence)
+ vma->fence->dirty = true;
+ }
+
+ obj->tiling_and_stride = tiling | stride;
+
+ /* Force the fence to be reacquired for GTT access */
+ i915_gem_release_mmap(obj);
+
+ /* Try to preallocate memory required to save swizzling on put-pages */
+ if (i915_gem_object_needs_bit17_swizzle(obj)) {
+ if (!obj->bit_17) {
+ obj->bit_17 = kcalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT),
+ sizeof(long), GFP_KERNEL);
+ }
+ } else {
+ kfree(obj->bit_17);
+ obj->bit_17 = NULL;
+ }
+
+ return 0;
+}
+
/**
- * i915_gem_set_tiling - IOCTL handler to set tiling mode
+ * i915_gem_set_tiling_ioctl - IOCTL handler to set tiling mode
* @dev: DRM device
* @data: data pointer for the ioctl
* @file: DRM file for the ioctl call
@@ -184,30 +337,19 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode)
* Zero on success, negative errno on failure.
*/
int
-i915_gem_set_tiling(struct drm_device *dev, void *data,
- struct drm_file *file)
+i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
{
struct drm_i915_gem_set_tiling *args = data;
- struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_i915_gem_object *obj;
- int err = 0;
-
- /* Make sure we don't cross-contaminate obj->tiling_and_stride */
- BUILD_BUG_ON(I915_TILING_LAST & STRIDE_MASK);
+ int err;
obj = i915_gem_object_lookup(file, args->handle);
if (!obj)
return -ENOENT;
- if (!i915_tiling_ok(dev_priv,
- args->stride, obj->base.size, args->tiling_mode)) {
- i915_gem_object_put(obj);
- return -EINVAL;
- }
-
- mutex_lock(&dev->struct_mutex);
- if (obj->pin_display || obj->framebuffer_references) {
- err = -EBUSY;
+ if (!i915_tiling_ok(obj, args->tiling_mode, args->stride)) {
+ err = -EINVAL;
goto err;
}
@@ -216,9 +358,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
args->stride = 0;
} else {
if (args->tiling_mode == I915_TILING_X)
- args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+ args->swizzle_mode = to_i915(dev)->mm.bit_6_swizzle_x;
else
- args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+ args->swizzle_mode = to_i915(dev)->mm.bit_6_swizzle_y;
/* Hide bit 17 swizzling from the user. This prevents old Mesa
* from aborting the application on sw fallbacks to bit 17,
@@ -240,79 +382,24 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
}
- if (args->tiling_mode != i915_gem_object_get_tiling(obj) ||
- args->stride != i915_gem_object_get_stride(obj)) {
- /* We need to rebind the object if its current allocation
- * no longer meets the alignment restrictions for its new
- * tiling mode. Otherwise we can just leave it alone, but
- * need to ensure that any fence register is updated before
- * the next fenced (either through the GTT or by the BLT unit
- * on older GPUs) access.
- *
- * After updating the tiling parameters, we then flag whether
- * we need to update an associated fence register. Note this
- * has to also include the unfenced register the GPU uses
- * whilst executing a fenced command for an untiled object.
- */
+ err = mutex_lock_interruptible(&dev->struct_mutex);
+ if (err)
+ goto err;
- err = i915_gem_object_fence_prepare(obj, args->tiling_mode);
- if (!err) {
- struct i915_vma *vma;
-
- mutex_lock(&obj->mm.lock);
- if (obj->mm.pages &&
- obj->mm.madv == I915_MADV_WILLNEED &&
- dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
- if (args->tiling_mode == I915_TILING_NONE) {
- GEM_BUG_ON(!obj->mm.quirked);
- __i915_gem_object_unpin_pages(obj);
- obj->mm.quirked = false;
- }
- if (!i915_gem_object_is_tiled(obj)) {
- GEM_BUG_ON(!obj->mm.quirked);
- __i915_gem_object_pin_pages(obj);
- obj->mm.quirked = true;
- }
- }
- mutex_unlock(&obj->mm.lock);
-
- list_for_each_entry(vma, &obj->vma_list, obj_link) {
- if (!vma->fence)
- continue;
-
- vma->fence->dirty = true;
- }
- obj->tiling_and_stride =
- args->stride | args->tiling_mode;
-
- /* Force the fence to be reacquired for GTT access */
- i915_gem_release_mmap(obj);
- }
- }
- /* we have to maintain this existing ABI... */
+ err = i915_gem_object_set_tiling(obj, args->tiling_mode, args->stride);
+ mutex_unlock(&dev->struct_mutex);
+
+ /* We have to maintain this existing ABI... */
args->stride = i915_gem_object_get_stride(obj);
args->tiling_mode = i915_gem_object_get_tiling(obj);
- /* Try to preallocate memory required to save swizzling on put-pages */
- if (i915_gem_object_needs_bit17_swizzle(obj)) {
- if (obj->bit_17 == NULL) {
- obj->bit_17 = kcalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT),
- sizeof(long), GFP_KERNEL);
- }
- } else {
- kfree(obj->bit_17);
- obj->bit_17 = NULL;
- }
-
err:
i915_gem_object_put(obj);
- mutex_unlock(&dev->struct_mutex);
-
return err;
}
/**
- * i915_gem_get_tiling - IOCTL handler to get tiling mode
+ * i915_gem_get_tiling_ioctl - IOCTL handler to get tiling mode
* @dev: DRM device
* @data: data pointer for the ioctl
* @file: DRM file for the ioctl call
@@ -325,8 +412,8 @@ err:
* Zero on success, negative errno on failure.
*/
int
-i915_gem_get_tiling(struct drm_device *dev, void *data,
- struct drm_file *file)
+i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
{
struct drm_i915_gem_get_tiling *args = data;
struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 396c6f0fd033..9cd22cda17af 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -121,6 +121,7 @@ static void __i915_error_advance(struct drm_i915_error_state_buf *e,
e->pos += len;
}
+__printf(2, 0)
static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
const char *f, va_list args)
{
diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h
index 6a0adafe0523..35cf9918d09a 100644
--- a/drivers/gpu/drm/i915/i915_guc_reg.h
+++ b/drivers/gpu/drm/i915/i915_guc_reg.h
@@ -61,12 +61,18 @@
#define DMA_ADDRESS_SPACE_GTT (8 << 16)
#define DMA_COPY_SIZE _MMIO(0xc310)
#define DMA_CTRL _MMIO(0xc314)
+#define HUC_UKERNEL (1<<9)
#define UOS_MOVE (1<<4)
#define START_DMA (1<<0)
#define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340)
+#define HUC_LOADING_AGENT_VCR (0<<1)
+#define HUC_LOADING_AGENT_GUC (1<<1)
#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */
#define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4)
+#define HUC_STATUS2 _MMIO(0xD3B0)
+#define HUC_FW_VERIFIED (1<<7)
+
/* Defines WOPCM space available to GuC firmware */
#define GUC_WOPCM_SIZE _MMIO(0xc050)
/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 710fbb9fc63f..8ced9e26f075 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -22,8 +22,6 @@
*
*/
#include <linux/circ_buf.h>
-#include <linux/debugfs.h>
-#include <linux/relay.h>
#include "i915_drv.h"
#include "intel_uc.h"
@@ -545,7 +543,7 @@ static void i915_guc_submit(struct drm_i915_gem_request *rq)
*/
/**
- * guc_allocate_vma() - Allocate a GGTT VMA for GuC usage
+ * intel_guc_allocate_vma() - Allocate a GGTT VMA for GuC usage
* @guc: the guc
* @size: size of area to allocate (both virtual space and memory)
*
@@ -557,7 +555,7 @@ static void i915_guc_submit(struct drm_i915_gem_request *rq)
*
* Return: A i915_vma if successful, otherwise an ERR_PTR.
*/
-static struct i915_vma *guc_allocate_vma(struct intel_guc *guc, u32 size)
+struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
struct drm_i915_gem_object *obj;
@@ -568,7 +566,7 @@ static struct i915_vma *guc_allocate_vma(struct intel_guc *guc, u32 size)
if (IS_ERR(obj))
return ERR_CAST(obj);
- vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
if (IS_ERR(vma))
goto err;
@@ -579,9 +577,6 @@ static struct i915_vma *guc_allocate_vma(struct intel_guc *guc, u32 size)
goto err;
}
- /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
- I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
-
return vma;
err:
@@ -721,7 +716,7 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
}
/* The first page is doorbell/proc_desc. Two followed pages are wq. */
- vma = guc_allocate_vma(guc, GUC_DB_SIZE + GUC_WQ_SIZE);
+ vma = intel_guc_allocate_vma(guc, GUC_DB_SIZE + GUC_WQ_SIZE);
if (IS_ERR(vma))
goto err;
@@ -777,488 +772,7 @@ err:
return NULL;
}
-/*
- * Sub buffer switch callback. Called whenever relay has to switch to a new
- * sub buffer, relay stays on the same sub buffer if 0 is returned.
- */
-static int subbuf_start_callback(struct rchan_buf *buf,
- void *subbuf,
- void *prev_subbuf,
- size_t prev_padding)
-{
- /* Use no-overwrite mode by default, where relay will stop accepting
- * new data if there are no empty sub buffers left.
- * There is no strict synchronization enforced by relay between Consumer
- * and Producer. In overwrite mode, there is a possibility of getting
- * inconsistent/garbled data, the producer could be writing on to the
- * same sub buffer from which Consumer is reading. This can't be avoided
- * unless Consumer is fast enough and can always run in tandem with
- * Producer.
- */
- if (relay_buf_full(buf))
- return 0;
-
- return 1;
-}
-
-/*
- * file_create() callback. Creates relay file in debugfs.
- */
-static struct dentry *create_buf_file_callback(const char *filename,
- struct dentry *parent,
- umode_t mode,
- struct rchan_buf *buf,
- int *is_global)
-{
- struct dentry *buf_file;
-
- /* This to enable the use of a single buffer for the relay channel and
- * correspondingly have a single file exposed to User, through which
- * it can collect the logs in order without any post-processing.
- * Need to set 'is_global' even if parent is NULL for early logging.
- */
- *is_global = 1;
-
- if (!parent)
- return NULL;
-
- /* Not using the channel filename passed as an argument, since for each
- * channel relay appends the corresponding CPU number to the filename
- * passed in relay_open(). This should be fine as relay just needs a
- * dentry of the file associated with the channel buffer and that file's
- * name need not be same as the filename passed as an argument.
- */
- buf_file = debugfs_create_file("guc_log", mode,
- parent, buf, &relay_file_operations);
- return buf_file;
-}
-
-/*
- * file_remove() default callback. Removes relay file in debugfs.
- */
-static int remove_buf_file_callback(struct dentry *dentry)
-{
- debugfs_remove(dentry);
- return 0;
-}
-
-/* relay channel callbacks */
-static struct rchan_callbacks relay_callbacks = {
- .subbuf_start = subbuf_start_callback,
- .create_buf_file = create_buf_file_callback,
- .remove_buf_file = remove_buf_file_callback,
-};
-
-static void guc_log_remove_relay_file(struct intel_guc *guc)
-{
- relay_close(guc->log.relay_chan);
-}
-
-static int guc_log_create_relay_channel(struct intel_guc *guc)
-{
- struct drm_i915_private *dev_priv = guc_to_i915(guc);
- struct rchan *guc_log_relay_chan;
- size_t n_subbufs, subbuf_size;
-
- /* Keep the size of sub buffers same as shared log buffer */
- subbuf_size = guc->log.vma->obj->base.size;
-
- /* Store up to 8 snapshots, which is large enough to buffer sufficient
- * boot time logs and provides enough leeway to User, in terms of
- * latency, for consuming the logs from relay. Also doesn't take
- * up too much memory.
- */
- n_subbufs = 8;
-
- guc_log_relay_chan = relay_open(NULL, NULL, subbuf_size,
- n_subbufs, &relay_callbacks, dev_priv);
- if (!guc_log_relay_chan) {
- DRM_ERROR("Couldn't create relay chan for GuC logging\n");
- return -ENOMEM;
- }
-
- GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size);
- guc->log.relay_chan = guc_log_relay_chan;
- return 0;
-}
-
-static int guc_log_create_relay_file(struct intel_guc *guc)
-{
- struct drm_i915_private *dev_priv = guc_to_i915(guc);
- struct dentry *log_dir;
- int ret;
-
- /* For now create the log file in /sys/kernel/debug/dri/0 dir */
- log_dir = dev_priv->drm.primary->debugfs_root;
-
- /* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
- * not mounted and so can't create the relay file.
- * The relay API seems to fit well with debugfs only, for availing relay
- * there are 3 requirements which can be met for debugfs file only in a
- * straightforward/clean manner :-
- * i) Need the associated dentry pointer of the file, while opening the
- * relay channel.
- * ii) Should be able to use 'relay_file_operations' fops for the file.
- * iii) Set the 'i_private' field of file's inode to the pointer of
- * relay channel buffer.
- */
- if (!log_dir) {
- DRM_ERROR("Debugfs dir not available yet for GuC log file\n");
- return -ENODEV;
- }
-
- ret = relay_late_setup_files(guc->log.relay_chan, "guc_log", log_dir);
- if (ret) {
- DRM_ERROR("Couldn't associate relay chan with file %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void guc_move_to_next_buf(struct intel_guc *guc)
-{
- /* Make sure the updates made in the sub buffer are visible when
- * Consumer sees the following update to offset inside the sub buffer.
- */
- smp_wmb();
-
- /* All data has been written, so now move the offset of sub buffer. */
- relay_reserve(guc->log.relay_chan, guc->log.vma->obj->base.size);
-
- /* Switch to the next sub buffer */
- relay_flush(guc->log.relay_chan);
-}
-
-static void *guc_get_write_buffer(struct intel_guc *guc)
-{
- if (!guc->log.relay_chan)
- return NULL;
-
- /* Just get the base address of a new sub buffer and copy data into it
- * ourselves. NULL will be returned in no-overwrite mode, if all sub
- * buffers are full. Could have used the relay_write() to indirectly
- * copy the data, but that would have been bit convoluted, as we need to
- * write to only certain locations inside a sub buffer which cannot be
- * done without using relay_reserve() along with relay_write(). So its
- * better to use relay_reserve() alone.
- */
- return relay_reserve(guc->log.relay_chan, 0);
-}
-
-static bool
-guc_check_log_buf_overflow(struct intel_guc *guc,
- enum guc_log_buffer_type type, unsigned int full_cnt)
-{
- unsigned int prev_full_cnt = guc->log.prev_overflow_count[type];
- bool overflow = false;
-
- if (full_cnt != prev_full_cnt) {
- overflow = true;
-
- guc->log.prev_overflow_count[type] = full_cnt;
- guc->log.total_overflow_count[type] += full_cnt - prev_full_cnt;
-
- if (full_cnt < prev_full_cnt) {
- /* buffer_full_cnt is a 4 bit counter */
- guc->log.total_overflow_count[type] += 16;
- }
- DRM_ERROR_RATELIMITED("GuC log buffer overflow\n");
- }
-
- return overflow;
-}
-
-static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
-{
- switch (type) {
- case GUC_ISR_LOG_BUFFER:
- return (GUC_LOG_ISR_PAGES + 1) * PAGE_SIZE;
- case GUC_DPC_LOG_BUFFER:
- return (GUC_LOG_DPC_PAGES + 1) * PAGE_SIZE;
- case GUC_CRASH_DUMP_LOG_BUFFER:
- return (GUC_LOG_CRASH_PAGES + 1) * PAGE_SIZE;
- default:
- MISSING_CASE(type);
- }
-
- return 0;
-}
-
-static void guc_read_update_log_buffer(struct intel_guc *guc)
-{
- unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt;
- struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state;
- struct guc_log_buffer_state log_buf_state_local;
- enum guc_log_buffer_type type;
- void *src_data, *dst_data;
- bool new_overflow;
-
- if (WARN_ON(!guc->log.buf_addr))
- return;
-
- /* Get the pointer to shared GuC log buffer */
- log_buf_state = src_data = guc->log.buf_addr;
-
- /* Get the pointer to local buffer to store the logs */
- log_buf_snapshot_state = dst_data = guc_get_write_buffer(guc);
-
- /* Actual logs are present from the 2nd page */
- src_data += PAGE_SIZE;
- dst_data += PAGE_SIZE;
-
- for (type = GUC_ISR_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
- /* Make a copy of the state structure, inside GuC log buffer
- * (which is uncached mapped), on the stack to avoid reading
- * from it multiple times.
- */
- memcpy(&log_buf_state_local, log_buf_state,
- sizeof(struct guc_log_buffer_state));
- buffer_size = guc_get_log_buffer_size(type);
- read_offset = log_buf_state_local.read_ptr;
- write_offset = log_buf_state_local.sampled_write_ptr;
- full_cnt = log_buf_state_local.buffer_full_cnt;
-
- /* Bookkeeping stuff */
- guc->log.flush_count[type] += log_buf_state_local.flush_to_file;
- new_overflow = guc_check_log_buf_overflow(guc, type, full_cnt);
-
- /* Update the state of shared log buffer */
- log_buf_state->read_ptr = write_offset;
- log_buf_state->flush_to_file = 0;
- log_buf_state++;
-
- if (unlikely(!log_buf_snapshot_state))
- continue;
-
- /* First copy the state structure in snapshot buffer */
- memcpy(log_buf_snapshot_state, &log_buf_state_local,
- sizeof(struct guc_log_buffer_state));
-
- /* The write pointer could have been updated by GuC firmware,
- * after sending the flush interrupt to Host, for consistency
- * set write pointer value to same value of sampled_write_ptr
- * in the snapshot buffer.
- */
- log_buf_snapshot_state->write_ptr = write_offset;
- log_buf_snapshot_state++;
-
- /* Now copy the actual logs. */
- if (unlikely(new_overflow)) {
- /* copy the whole buffer in case of overflow */
- read_offset = 0;
- write_offset = buffer_size;
- } else if (unlikely((read_offset > buffer_size) ||
- (write_offset > buffer_size))) {
- DRM_ERROR("invalid log buffer state\n");
- /* copy whole buffer as offsets are unreliable */
- read_offset = 0;
- write_offset = buffer_size;
- }
-
- /* Just copy the newly written data */
- if (read_offset > write_offset) {
- i915_memcpy_from_wc(dst_data, src_data, write_offset);
- bytes_to_copy = buffer_size - read_offset;
- } else {
- bytes_to_copy = write_offset - read_offset;
- }
- i915_memcpy_from_wc(dst_data + read_offset,
- src_data + read_offset, bytes_to_copy);
-
- src_data += buffer_size;
- dst_data += buffer_size;
- }
-
- if (log_buf_snapshot_state)
- guc_move_to_next_buf(guc);
- else {
- /* Used rate limited to avoid deluge of messages, logs might be
- * getting consumed by User at a slow rate.
- */
- DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
- guc->log.capture_miss_count++;
- }
-}
-
-static void guc_capture_logs_work(struct work_struct *work)
-{
- struct drm_i915_private *dev_priv =
- container_of(work, struct drm_i915_private, guc.log.flush_work);
-
- i915_guc_capture_logs(dev_priv);
-}
-
-static void guc_log_cleanup(struct intel_guc *guc)
-{
- struct drm_i915_private *dev_priv = guc_to_i915(guc);
-
- lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
- /* First disable the flush interrupt */
- gen9_disable_guc_interrupts(dev_priv);
- if (guc->log.flush_wq)
- destroy_workqueue(guc->log.flush_wq);
-
- guc->log.flush_wq = NULL;
-
- if (guc->log.relay_chan)
- guc_log_remove_relay_file(guc);
-
- guc->log.relay_chan = NULL;
-
- if (guc->log.buf_addr)
- i915_gem_object_unpin_map(guc->log.vma->obj);
-
- guc->log.buf_addr = NULL;
-}
-
-static int guc_log_create_extras(struct intel_guc *guc)
-{
- struct drm_i915_private *dev_priv = guc_to_i915(guc);
- void *vaddr;
- int ret;
-
- lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
- /* Nothing to do */
- if (i915.guc_log_level < 0)
- return 0;
-
- if (!guc->log.buf_addr) {
- /* Create a WC (Uncached for read) vmalloc mapping of log
- * buffer pages, so that we can directly get the data
- * (up-to-date) from memory.
- */
- vaddr = i915_gem_object_pin_map(guc->log.vma->obj, I915_MAP_WC);
- if (IS_ERR(vaddr)) {
- ret = PTR_ERR(vaddr);
- DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
- return ret;
- }
-
- guc->log.buf_addr = vaddr;
- }
-
- if (!guc->log.relay_chan) {
- /* Create a relay channel, so that we have buffers for storing
- * the GuC firmware logs, the channel will be linked with a file
- * later on when debugfs is registered.
- */
- ret = guc_log_create_relay_channel(guc);
- if (ret)
- return ret;
- }
-
- if (!guc->log.flush_wq) {
- INIT_WORK(&guc->log.flush_work, guc_capture_logs_work);
-
- /*
- * GuC log buffer flush work item has to do register access to
- * send the ack to GuC and this work item, if not synced before
- * suspend, can potentially get executed after the GFX device is
- * suspended.
- * By marking the WQ as freezable, we don't have to bother about
- * flushing of this work item from the suspend hooks, the pending
- * work item if any will be either executed before the suspend
- * or scheduled later on resume. This way the handling of work
- * item can be kept same between system suspend & rpm suspend.
- */
- guc->log.flush_wq = alloc_ordered_workqueue("i915-guc_log",
- WQ_HIGHPRI | WQ_FREEZABLE);
- if (guc->log.flush_wq == NULL) {
- DRM_ERROR("Couldn't allocate the wq for GuC logging\n");
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-static void guc_log_create(struct intel_guc *guc)
-{
- struct i915_vma *vma;
- unsigned long offset;
- uint32_t size, flags;
-
- if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
- i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
-
- /* The first page is to save log buffer state. Allocate one
- * extra page for others in case for overlap */
- size = (1 + GUC_LOG_DPC_PAGES + 1 +
- GUC_LOG_ISR_PAGES + 1 +
- GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
-
- vma = guc->log.vma;
- if (!vma) {
- /* We require SSE 4.1 for fast reads from the GuC log buffer and
- * it should be present on the chipsets supporting GuC based
- * submisssions.
- */
- if (WARN_ON(!i915_has_memcpy_from_wc())) {
- /* logging will not be enabled */
- i915.guc_log_level = -1;
- return;
- }
-
- vma = guc_allocate_vma(guc, size);
- if (IS_ERR(vma)) {
- /* logging will be off */
- i915.guc_log_level = -1;
- return;
- }
-
- guc->log.vma = vma;
-
- if (guc_log_create_extras(guc)) {
- guc_log_cleanup(guc);
- i915_vma_unpin_and_release(&guc->log.vma);
- i915.guc_log_level = -1;
- return;
- }
- }
-
- /* each allocated unit is a page */
- flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
- (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
- (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
- (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
-
- offset = guc_ggtt_offset(vma) >> PAGE_SHIFT; /* in pages */
- guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
-}
-
-static int guc_log_late_setup(struct intel_guc *guc)
-{
- struct drm_i915_private *dev_priv = guc_to_i915(guc);
- int ret;
-
- lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
- if (i915.guc_log_level < 0)
- return -EINVAL;
-
- /* If log_level was set as -1 at boot time, then setup needed to
- * handle log buffer flush interrupts would not have been done yet,
- * so do that now.
- */
- ret = guc_log_create_extras(guc);
- if (ret)
- goto err;
-
- ret = guc_log_create_relay_file(guc);
- if (ret)
- goto err;
-
- return 0;
-err:
- guc_log_cleanup(guc);
- /* logging will remain off */
- i915.guc_log_level = -1;
- return ret;
-}
static void guc_policies_init(struct guc_policies *policies)
{
@@ -1301,7 +815,7 @@ static void guc_addon_create(struct intel_guc *guc)
vma = guc->ads_vma;
if (!vma) {
- vma = guc_allocate_vma(guc, PAGE_ALIGN(size));
+ vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(size));
if (IS_ERR(vma))
return;
@@ -1376,13 +890,13 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
if (guc->ctx_pool_vma)
return 0; /* already allocated */
- vma = guc_allocate_vma(guc, gemsize);
+ vma = intel_guc_allocate_vma(guc, gemsize);
if (IS_ERR(vma))
return PTR_ERR(vma);
guc->ctx_pool_vma = vma;
ida_init(&guc->ctx_ids);
- guc_log_create(guc);
+ intel_guc_log_create(guc);
guc_addon_create(guc);
guc->execbuf_client = guc_client_alloc(dev_priv,
@@ -1484,7 +998,7 @@ int intel_guc_suspend(struct drm_i915_private *dev_priv)
struct i915_gem_context *ctx;
u32 data[3];
- if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
+ if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
return 0;
gen9_disable_guc_interrupts(dev_priv);
@@ -1511,7 +1025,7 @@ int intel_guc_resume(struct drm_i915_private *dev_priv)
struct i915_gem_context *ctx;
u32 data[3];
- if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
+ if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
return 0;
if (i915.guc_log_level >= 0)
@@ -1527,103 +1041,4 @@ int intel_guc_resume(struct drm_i915_private *dev_priv)
return intel_guc_send(guc, data, ARRAY_SIZE(data));
}
-void i915_guc_capture_logs(struct drm_i915_private *dev_priv)
-{
- guc_read_update_log_buffer(&dev_priv->guc);
-
- /* Generally device is expected to be active only at this
- * time, so get/put should be really quick.
- */
- intel_runtime_pm_get(dev_priv);
- intel_guc_log_flush_complete(&dev_priv->guc);
- intel_runtime_pm_put(dev_priv);
-}
-
-void i915_guc_flush_logs(struct drm_i915_private *dev_priv)
-{
- if (!i915.enable_guc_submission || (i915.guc_log_level < 0))
- return;
-
- /* First disable the interrupts, will be renabled afterwards */
- gen9_disable_guc_interrupts(dev_priv);
-
- /* Before initiating the forceful flush, wait for any pending/ongoing
- * flush to complete otherwise forceful flush may not actually happen.
- */
- flush_work(&dev_priv->guc.log.flush_work);
-
- /* Ask GuC to update the log buffer state */
- intel_guc_log_flush(&dev_priv->guc);
-
- /* GuC would have updated log buffer by now, so capture it */
- i915_guc_capture_logs(dev_priv);
-}
-
-void i915_guc_unregister(struct drm_i915_private *dev_priv)
-{
- if (!i915.enable_guc_submission)
- return;
- mutex_lock(&dev_priv->drm.struct_mutex);
- guc_log_cleanup(&dev_priv->guc);
- mutex_unlock(&dev_priv->drm.struct_mutex);
-}
-
-void i915_guc_register(struct drm_i915_private *dev_priv)
-{
- if (!i915.enable_guc_submission)
- return;
-
- mutex_lock(&dev_priv->drm.struct_mutex);
- guc_log_late_setup(&dev_priv->guc);
- mutex_unlock(&dev_priv->drm.struct_mutex);
-}
-
-int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
-{
- union guc_log_control log_param;
- int ret;
-
- log_param.value = control_val;
-
- if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
- log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
- return -EINVAL;
-
- /* This combination doesn't make sense & won't have any effect */
- if (!log_param.logging_enabled && (i915.guc_log_level < 0))
- return 0;
-
- ret = intel_guc_log_control(&dev_priv->guc, log_param.value);
- if (ret < 0) {
- DRM_DEBUG_DRIVER("guc_logging_control action failed %d\n", ret);
- return ret;
- }
-
- i915.guc_log_level = log_param.verbosity;
-
- /* If log_level was set as -1 at boot time, then the relay channel file
- * wouldn't have been created by now and interrupts also would not have
- * been enabled.
- */
- if (!dev_priv->guc.log.relay_chan) {
- ret = guc_log_late_setup(&dev_priv->guc);
- if (!ret)
- gen9_enable_guc_interrupts(dev_priv);
- } else if (!log_param.logging_enabled) {
- /* Once logging is disabled, GuC won't generate logs & send an
- * interrupt. But there could be some data in the log buffer
- * which is yet to be captured. So request GuC to update the log
- * buffer state and then collect the left over logs.
- */
- i915_guc_flush_logs(dev_priv);
-
- /* As logging is disabled, update log level to reflect that */
- i915.guc_log_level = -1;
- } else {
- /* In case interrupts were disabled, enable them now */
- gen9_enable_guc_interrupts(dev_priv);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a0e70f5b3aad..6fefc34ef602 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1170,6 +1170,9 @@ static void gen6_pm_rps_work(struct work_struct *work)
adj *= 2;
else /* CHV needs even encode values */
adj = IS_CHERRYVIEW(dev_priv) ? 2 : 1;
+
+ if (new_delay >= dev_priv->rps.max_freq_softlimit)
+ adj = 0;
/*
* For better performance, jump directly
* to RPe if we're below it.
@@ -1191,6 +1194,9 @@ static void gen6_pm_rps_work(struct work_struct *work)
adj *= 2;
else /* CHV needs even encode values */
adj = IS_CHERRYVIEW(dev_priv) ? -2 : -1;
+
+ if (new_delay <= dev_priv->rps.min_freq_softlimit)
+ adj = 0;
} else { /* unknown event */
adj = 0;
}
@@ -1553,41 +1559,68 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
{
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
struct intel_pipe_crc_entry *entry;
+ struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+ struct drm_driver *driver = dev_priv->drm.driver;
+ uint32_t crcs[5];
int head, tail;
spin_lock(&pipe_crc->lock);
+ if (pipe_crc->source) {
+ if (!pipe_crc->entries) {
+ spin_unlock(&pipe_crc->lock);
+ DRM_DEBUG_KMS("spurious interrupt\n");
+ return;
+ }
- if (!pipe_crc->entries) {
- spin_unlock(&pipe_crc->lock);
- DRM_DEBUG_KMS("spurious interrupt\n");
- return;
- }
-
- head = pipe_crc->head;
- tail = pipe_crc->tail;
+ head = pipe_crc->head;
+ tail = pipe_crc->tail;
- if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
- spin_unlock(&pipe_crc->lock);
- DRM_ERROR("CRC buffer overflowing\n");
- return;
- }
+ if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
+ spin_unlock(&pipe_crc->lock);
+ DRM_ERROR("CRC buffer overflowing\n");
+ return;
+ }
- entry = &pipe_crc->entries[head];
+ entry = &pipe_crc->entries[head];
- entry->frame = dev_priv->drm.driver->get_vblank_counter(&dev_priv->drm,
- pipe);
- entry->crc[0] = crc0;
- entry->crc[1] = crc1;
- entry->crc[2] = crc2;
- entry->crc[3] = crc3;
- entry->crc[4] = crc4;
+ entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe);
+ entry->crc[0] = crc0;
+ entry->crc[1] = crc1;
+ entry->crc[2] = crc2;
+ entry->crc[3] = crc3;
+ entry->crc[4] = crc4;
- head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
- pipe_crc->head = head;
+ head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
+ pipe_crc->head = head;
- spin_unlock(&pipe_crc->lock);
+ spin_unlock(&pipe_crc->lock);
- wake_up_interruptible(&pipe_crc->wq);
+ wake_up_interruptible(&pipe_crc->wq);
+ } else {
+ /*
+ * For some not yet identified reason, the first CRC is
+ * bonkers. So let's just wait for the next vblank and read
+ * out the buggy result.
+ *
+ * On CHV sometimes the second CRC is bonkers as well, so
+ * don't trust that one either.
+ */
+ if (pipe_crc->skipped == 0 ||
+ (IS_CHERRYVIEW(dev_priv) && pipe_crc->skipped == 1)) {
+ pipe_crc->skipped++;
+ spin_unlock(&pipe_crc->lock);
+ return;
+ }
+ spin_unlock(&pipe_crc->lock);
+ crcs[0] = crc0;
+ crcs[1] = crc1;
+ crcs[2] = crc2;
+ crcs[3] = crc3;
+ crcs[4] = crc4;
+ drm_crtc_add_crc_entry(&crtc->base, true,
+ drm_accurate_vblank_count(&crtc->base),
+ crcs);
+ }
}
#else
static inline void
@@ -2703,12 +2736,13 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv)
* i915_handle_error - handle a gpu error
* @dev_priv: i915 device private
* @engine_mask: mask representing engines that are hung
+ * @fmt: Error message format string
+ *
* Do some basic checking of register state at error time and
* dump it to the syslog. Also call i915_capture_error_state() to make
* sure we get a record and make it available in debugfs. Fire a uevent
* so userspace knows something bad happened (should trigger collection
* of a ring dump etc.).
- * @fmt: Error message format string
*/
void i915_handle_error(struct drm_i915_private *dev_priv,
u32 engine_mask,
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 00970aa77afa..72f9f36ae5ce 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3597,9 +3597,12 @@ enum {
#define EDP_PSR_PERF_CNT_MASK 0xffffff
#define EDP_PSR_DEBUG_CTL _MMIO(dev_priv->psr_mmio_base + 0x60)
-#define EDP_PSR_DEBUG_MASK_LPSP (1<<27)
-#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26)
-#define EDP_PSR_DEBUG_MASK_HPD (1<<25)
+#define EDP_PSR_DEBUG_MASK_MAX_SLEEP (1<<28)
+#define EDP_PSR_DEBUG_MASK_LPSP (1<<27)
+#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26)
+#define EDP_PSR_DEBUG_MASK_HPD (1<<25)
+#define EDP_PSR_DEBUG_MASK_DISP_REG_WRITE (1<<16)
+#define EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1<<15)
#define EDP_PSR2_CTL _MMIO(0x6f900)
#define EDP_PSR2_ENABLE (1<<31)
@@ -3614,6 +3617,11 @@ enum {
#define EDP_PSR2_FRAME_BEFORE_SU_SHIFT 4
#define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4)
#define EDP_PSR2_IDLE_MASK 0xf
+#define EDP_FRAMES_BEFORE_SU_ENTRY (1<<4)
+
+#define EDP_PSR2_STATUS_CTL _MMIO(0x6f940)
+#define EDP_PSR2_STATUS_STATE_MASK (0xf<<28)
+#define EDP_PSR2_STATUS_STATE_SHIFT 28
/* VGA port control */
#define ADPA _MMIO(0x61100)
@@ -6446,6 +6454,12 @@ enum {
#define BDW_DPRS_MASK_VBLANK_SRD (1 << 0)
#define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
+#define CHICKEN_TRANS_A 0x420c0
+#define CHICKEN_TRANS_B 0x420c4
+#define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B)
+#define PSR2_VSC_ENABLE_PROG_HEADER (1<<12)
+#define PSR2_ADD_VERTICAL_LINE_COUNT (1<<15)
+
#define DISP_ARB_CTL _MMIO(0x45000)
#define DISP_FBC_MEMORY_WAKE (1<<31)
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
index f5a88092dacf..40f4e5efaf83 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -63,6 +63,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence)
static inline void debug_fence_free(struct i915_sw_fence *fence)
{
debug_object_free(fence, &i915_sw_fence_debug_descr);
+ smp_wmb(); /* flush the change in state before reallocation */
}
static inline void debug_fence_assert(struct i915_sw_fence *fence)
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 40c0ac70d79d..376ac957cd1c 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -58,7 +58,7 @@ static u32 calc_residency(struct drm_i915_private *dev_priv,
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
units <<= 8;
- } else if (IS_BROXTON(dev_priv)) {
+ } else if (IS_GEN9_LP(dev_priv)) {
units = 1;
div = 1200; /* 833.33ns */
}
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 18ae37c411fd..4461df5a94fe 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -450,9 +450,9 @@ TRACE_EVENT(i915_gem_evict_vm,
TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm)
);
-TRACE_EVENT(i915_gem_evict_vma,
- TP_PROTO(struct i915_vma *vma, unsigned int flags),
- TP_ARGS(vma, flags),
+TRACE_EVENT(i915_gem_evict_node,
+ TP_PROTO(struct i915_address_space *vm, struct drm_mm_node *node, unsigned int flags),
+ TP_ARGS(vm, node, flags),
TP_STRUCT__entry(
__field(u32, dev)
@@ -464,11 +464,11 @@ TRACE_EVENT(i915_gem_evict_vma,
),
TP_fast_assign(
- __entry->dev = vma->vm->i915->drm.primary->index;
- __entry->vm = vma->vm;
- __entry->start = vma->node.start;
- __entry->size = vma->node.size;
- __entry->color = vma->node.color;
+ __entry->dev = vm->i915->drm.primary->index;
+ __entry->vm = vm;
+ __entry->start = node->start;
+ __entry->size = node->size;
+ __entry->color = node->color;
__entry->flags = flags;
),
diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
index dae340cfc6c7..d0abfd08a01c 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.c
+++ b/drivers/gpu/drm/i915/i915_vgpu.c
@@ -116,22 +116,20 @@ void intel_vgt_deballoon(struct drm_i915_private *dev_priv)
memset(&bl_info, 0, sizeof(bl_info));
}
-static int vgt_balloon_space(struct drm_mm *mm,
+static int vgt_balloon_space(struct i915_ggtt *ggtt,
struct drm_mm_node *node,
unsigned long start, unsigned long end)
{
unsigned long size = end - start;
- if (start == end)
+ if (start >= end)
return -EINVAL;
DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n",
start, end, size / 1024);
-
- node->start = start;
- node->size = size;
-
- return drm_mm_reserve_node(mm, node);
+ return i915_gem_gtt_reserve(&ggtt->base, node,
+ size, start, I915_COLOR_UNEVICTABLE,
+ 0);
}
/**
@@ -214,10 +212,8 @@ int intel_vgt_balloon(struct drm_i915_private *dev_priv)
/* Unmappable graphic memory ballooning */
if (unmappable_base > ggtt->mappable_end) {
- ret = vgt_balloon_space(&ggtt->base.mm,
- &bl_info.space[2],
- ggtt->mappable_end,
- unmappable_base);
+ ret = vgt_balloon_space(ggtt, &bl_info.space[2],
+ ggtt->mappable_end, unmappable_base);
if (ret)
goto err;
@@ -228,18 +224,15 @@ int intel_vgt_balloon(struct drm_i915_private *dev_priv)
* because it is reserved to the guard page.
*/
if (unmappable_end < ggtt_end - PAGE_SIZE) {
- ret = vgt_balloon_space(&ggtt->base.mm,
- &bl_info.space[3],
- unmappable_end,
- ggtt_end - PAGE_SIZE);
+ ret = vgt_balloon_space(ggtt, &bl_info.space[3],
+ unmappable_end, ggtt_end - PAGE_SIZE);
if (ret)
goto err;
}
/* Mappable graphic memory ballooning */
if (mappable_base > ggtt->base.start) {
- ret = vgt_balloon_space(&ggtt->base.mm,
- &bl_info.space[0],
+ ret = vgt_balloon_space(ggtt, &bl_info.space[0],
ggtt->base.start, mappable_base);
if (ret)
@@ -247,10 +240,8 @@ int intel_vgt_balloon(struct drm_i915_private *dev_priv)
}
if (mappable_end < ggtt->mappable_end) {
- ret = vgt_balloon_space(&ggtt->base.mm,
- &bl_info.space[1],
- mappable_end,
- ggtt->mappable_end);
+ ret = vgt_balloon_space(ggtt, &bl_info.space[1],
+ mappable_end, ggtt->mappable_end);
if (ret)
goto err;
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 58f2483362ad..155906e84812 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -45,6 +45,7 @@ i915_vma_retire(struct i915_gem_active *active,
if (i915_vma_is_active(vma))
return;
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
if (unlikely(i915_vma_is_closed(vma) && !i915_vma_is_pinned(vma)))
WARN_ON(i915_vma_unbind(vma));
@@ -69,17 +70,15 @@ i915_vma_retire(struct i915_gem_active *active,
}
static struct i915_vma *
-__i915_vma_create(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view)
+vma_create(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
{
struct i915_vma *vma;
struct rb_node *rb, **p;
int i;
- GEM_BUG_ON(vm->closed);
-
- vma = kmem_cache_zalloc(to_i915(obj->base.dev)->vmas, GFP_KERNEL);
+ vma = kmem_cache_zalloc(vm->i915->vmas, GFP_KERNEL);
if (vma == NULL)
return ERR_PTR(-ENOMEM);
@@ -87,29 +86,50 @@ __i915_vma_create(struct drm_i915_gem_object *obj,
for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
init_request_active(&vma->last_read[i], i915_vma_retire);
init_request_active(&vma->last_fence, NULL);
- list_add(&vma->vm_link, &vm->unbound_list);
vma->vm = vm;
vma->obj = obj;
vma->size = obj->base.size;
+ vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
- if (view) {
+ if (view && view->type != I915_GGTT_VIEW_NORMAL) {
vma->ggtt_view = *view;
if (view->type == I915_GGTT_VIEW_PARTIAL) {
GEM_BUG_ON(range_overflows_t(u64,
- view->params.partial.offset,
- view->params.partial.size,
+ view->partial.offset,
+ view->partial.size,
obj->base.size >> PAGE_SHIFT));
- vma->size = view->params.partial.size;
+ vma->size = view->partial.size;
vma->size <<= PAGE_SHIFT;
GEM_BUG_ON(vma->size >= obj->base.size);
} else if (view->type == I915_GGTT_VIEW_ROTATED) {
- vma->size =
- intel_rotation_info_size(&view->params.rotated);
+ vma->size = intel_rotation_info_size(&view->rotated);
vma->size <<= PAGE_SHIFT;
}
}
+ if (unlikely(vma->size > vm->total))
+ goto err_vma;
+
+ GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
+
if (i915_is_ggtt(vm)) {
+ if (unlikely(overflows_type(vma->size, u32)))
+ goto err_vma;
+
+ vma->fence_size = i915_gem_fence_size(vm->i915, vma->size,
+ i915_gem_object_get_tiling(obj),
+ i915_gem_object_get_stride(obj));
+ if (unlikely(vma->fence_size < vma->size || /* overflow */
+ vma->fence_size > vm->total))
+ goto err_vma;
+
+ GEM_BUG_ON(!IS_ALIGNED(vma->fence_size, I915_GTT_MIN_ALIGNMENT));
+
+ vma->fence_alignment = i915_gem_fence_alignment(vm->i915, vma->size,
+ i915_gem_object_get_tiling(obj),
+ i915_gem_object_get_stride(obj));
+ GEM_BUG_ON(!is_power_of_2(vma->fence_alignment));
+
vma->flags |= I915_VMA_GGTT;
list_add(&vma->obj_link, &obj->vma_list);
} else {
@@ -131,20 +151,74 @@ __i915_vma_create(struct drm_i915_gem_object *obj,
}
rb_link_node(&vma->obj_node, rb, p);
rb_insert_color(&vma->obj_node, &obj->vma_tree);
+ list_add(&vma->vm_link, &vm->unbound_list);
return vma;
+
+err_vma:
+ kmem_cache_free(vm->i915->vmas, vma);
+ return ERR_PTR(-E2BIG);
}
+static struct i915_vma *
+vma_lookup(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
+{
+ struct rb_node *rb;
+
+ rb = obj->vma_tree.rb_node;
+ while (rb) {
+ struct i915_vma *vma = rb_entry(rb, struct i915_vma, obj_node);
+ long cmp;
+
+ cmp = i915_vma_compare(vma, vm, view);
+ if (cmp == 0)
+ return vma;
+
+ if (cmp < 0)
+ rb = rb->rb_right;
+ else
+ rb = rb->rb_left;
+ }
+
+ return NULL;
+}
+
+/**
+ * i915_vma_instance - return the singleton instance of the VMA
+ * @obj: parent &struct drm_i915_gem_object to be mapped
+ * @vm: address space in which the mapping is located
+ * @view: additional mapping requirements
+ *
+ * i915_vma_instance() looks up an existing VMA of the @obj in the @vm with
+ * the same @view characteristics. If a match is not found, one is created.
+ * Once created, the VMA is kept until either the object is freed, or the
+ * address space is closed.
+ *
+ * Must be called with struct_mutex held.
+ *
+ * Returns the vma, or an error pointer.
+ */
struct i915_vma *
-i915_vma_create(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view)
+i915_vma_instance(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
{
+ struct i915_vma *vma;
+
lockdep_assert_held(&obj->base.dev->struct_mutex);
GEM_BUG_ON(view && !i915_is_ggtt(vm));
- GEM_BUG_ON(i915_gem_obj_to_vma(obj, vm, view));
+ GEM_BUG_ON(vm->closed);
+
+ vma = vma_lookup(obj, vm, view);
+ if (!vma)
+ vma = vma_create(obj, vm, view);
- return __i915_vma_create(obj, vm, view);
+ GEM_BUG_ON(!IS_ERR(vma) && i915_vma_is_closed(vma));
+ GEM_BUG_ON(!IS_ERR(vma) && i915_vma_compare(vma, vm, view));
+ GEM_BUG_ON(!IS_ERR(vma) && vma_lookup(obj, vm, view) != vma);
+ return vma;
}
/**
@@ -195,6 +269,7 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
return ret;
}
+ trace_i915_vma_bind(vma, bind_flags);
ret = vma->vm->bind_vma(vma, cache_level, bind_flags);
if (ret)
return ret;
@@ -258,7 +333,8 @@ i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
if (vma->node.size < size)
return true;
- if (alignment && vma->node.start & (alignment - 1))
+ GEM_BUG_ON(alignment && !is_power_of_2(alignment));
+ if (alignment && !IS_ALIGNED(vma->node.start, alignment))
return true;
if (flags & PIN_MAPPABLE && !i915_vma_is_map_and_fenceable(vma))
@@ -277,31 +353,24 @@ i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
{
- struct drm_i915_gem_object *obj = vma->obj;
- struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
bool mappable, fenceable;
- u32 fence_size, fence_alignment;
-
- fence_size = i915_gem_get_ggtt_size(dev_priv,
- vma->size,
- i915_gem_object_get_tiling(obj));
- fence_alignment = i915_gem_get_ggtt_alignment(dev_priv,
- vma->size,
- i915_gem_object_get_tiling(obj),
- true);
-
- fenceable = (vma->node.size == fence_size &&
- (vma->node.start & (fence_alignment - 1)) == 0);
- mappable = (vma->node.start + fence_size <=
- dev_priv->ggtt.mappable_end);
+ GEM_BUG_ON(!i915_vma_is_ggtt(vma));
+ GEM_BUG_ON(!vma->fence_size);
/*
* Explicitly disable for rotated VMA since the display does not
* need the fence and the VMA is not accessible to other users.
*/
- if (mappable && fenceable &&
- vma->ggtt_view.type != I915_GGTT_VIEW_ROTATED)
+ if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
+ return;
+
+ fenceable = (vma->node.size >= vma->fence_size &&
+ IS_ALIGNED(vma->node.start, vma->fence_alignment));
+
+ mappable = vma->node.start + vma->fence_size <= i915_vm_to_ggtt(vma->vm)->mappable_end;
+
+ if (mappable && fenceable)
vma->flags |= I915_VMA_CAN_FENCE;
else
vma->flags &= ~I915_VMA_CAN_FENCE;
@@ -368,22 +437,26 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
size = max(size, vma->size);
- if (flags & PIN_MAPPABLE)
- size = i915_gem_get_ggtt_size(dev_priv, size,
- i915_gem_object_get_tiling(obj));
+ alignment = max(alignment, vma->display_alignment);
+ if (flags & PIN_MAPPABLE) {
+ size = max_t(typeof(size), size, vma->fence_size);
+ alignment = max_t(typeof(alignment),
+ alignment, vma->fence_alignment);
+ }
- alignment = max(max(alignment, vma->display_alignment),
- i915_gem_get_ggtt_alignment(dev_priv, size,
- i915_gem_object_get_tiling(obj),
- flags & PIN_MAPPABLE));
+ GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
+ GEM_BUG_ON(!IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT));
+ GEM_BUG_ON(!is_power_of_2(alignment));
start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
+ GEM_BUG_ON(!IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
end = vma->vm->total;
if (flags & PIN_MAPPABLE)
end = min_t(u64, end, dev_priv->ggtt.mappable_end);
if (flags & PIN_ZONE_4G)
- end = min_t(u64, end, (1ULL << 32) - PAGE_SIZE);
+ end = min_t(u64, end, (1ULL << 32) - I915_GTT_PAGE_SIZE);
+ GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
/* If binding the object/GGTT view requires more space than the entire
* aperture has, reject it early before evicting everything in a vain
@@ -403,65 +476,28 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
if (flags & PIN_OFFSET_FIXED) {
u64 offset = flags & PIN_OFFSET_MASK;
- if (offset & (alignment - 1) ||
+ if (!IS_ALIGNED(offset, alignment) ||
range_overflows(offset, size, end)) {
ret = -EINVAL;
goto err_unpin;
}
- vma->node.start = offset;
- vma->node.size = size;
- vma->node.color = obj->cache_level;
- ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node);
- if (ret) {
- ret = i915_gem_evict_for_vma(vma, flags);
- if (ret == 0)
- ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node);
- if (ret)
- goto err_unpin;
- }
+ ret = i915_gem_gtt_reserve(vma->vm, &vma->node,
+ size, offset, obj->cache_level,
+ flags);
+ if (ret)
+ goto err_unpin;
} else {
- u32 search_flag, alloc_flag;
-
- if (flags & PIN_HIGH) {
- search_flag = DRM_MM_SEARCH_BELOW;
- alloc_flag = DRM_MM_CREATE_TOP;
- } else {
- search_flag = DRM_MM_SEARCH_DEFAULT;
- alloc_flag = DRM_MM_CREATE_DEFAULT;
- }
-
- /* We only allocate in PAGE_SIZE/GTT_PAGE_SIZE (4096) chunks,
- * so we know that we always have a minimum alignment of 4096.
- * The drm_mm range manager is optimised to return results
- * with zero alignment, so where possible use the optimal
- * path.
- */
- if (alignment <= 4096)
- alignment = 0;
-
-search_free:
- ret = drm_mm_insert_node_in_range_generic(&vma->vm->mm,
- &vma->node,
- size, alignment,
- obj->cache_level,
- start, end,
- search_flag,
- alloc_flag);
- if (ret) {
- ret = i915_gem_evict_something(vma->vm, size, alignment,
- obj->cache_level,
- start, end,
- flags);
- if (ret == 0)
- goto search_free;
-
+ ret = i915_gem_gtt_insert(vma->vm, &vma->node,
+ size, alignment, obj->cache_level,
+ start, end, flags);
+ if (ret)
goto err_unpin;
- }
GEM_BUG_ON(vma->node.start < start);
GEM_BUG_ON(vma->node.start + vma->node.size > end);
}
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level));
list_move_tail(&obj->global_link, &dev_priv->mm.bound_list);
@@ -504,6 +540,7 @@ int __i915_vma_do_pin(struct i915_vma *vma,
if ((bound ^ vma->flags) & I915_VMA_GLOBAL_BIND)
__i915_vma_set_map_and_fenceable(vma);
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags));
return 0;
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index e3b2b3b1e056..e39d922cfb6f 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -55,6 +55,9 @@ struct i915_vma {
u64 size;
u64 display_alignment;
+ u32 fence_size;
+ u32 fence_alignment;
+
unsigned int flags;
/**
* How many users have pinned this object in GTT space. The following
@@ -109,9 +112,9 @@ struct i915_vma {
};
struct i915_vma *
-i915_vma_create(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- const struct i915_ggtt_view *view);
+i915_vma_instance(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view);
void i915_vma_unpin_and_release(struct i915_vma **p_vma);
@@ -196,15 +199,30 @@ i915_vma_compare(struct i915_vma *vma,
if (cmp)
return cmp;
+ BUILD_BUG_ON(I915_GGTT_VIEW_NORMAL != 0);
+ cmp = vma->ggtt_view.type;
if (!view)
- return vma->ggtt_view.type;
+ return cmp;
- if (vma->ggtt_view.type != view->type)
- return vma->ggtt_view.type - view->type;
+ cmp -= view->type;
+ if (cmp)
+ return cmp;
- return memcmp(&vma->ggtt_view.params,
- &view->params,
- sizeof(view->params));
+ /* ggtt_view.type also encodes its size so that we both distinguish
+ * different views using it as a "type" and also use a compact (no
+ * accessing of uninitialised padding bytes) memcmp without storing
+ * an extra parameter or adding more code.
+ *
+ * To ensure that the memcmp is valid for all branches of the union,
+ * even though the code looks like it is just comparing one branch,
+ * we assert above that all branches have the same address, and that
+ * each branch has a unique type/size.
+ */
+ BUILD_BUG_ON(I915_GGTT_VIEW_NORMAL >= I915_GGTT_VIEW_PARTIAL);
+ BUILD_BUG_ON(I915_GGTT_VIEW_PARTIAL >= I915_GGTT_VIEW_ROTATED);
+ BUILD_BUG_ON(offsetof(typeof(*view), rotated) !=
+ offsetof(typeof(*view), partial));
+ return memcmp(&vma->ggtt_view.partial, &view->partial, view->type);
}
int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
@@ -229,8 +247,11 @@ i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
/* Pin early to prevent the shrinker/eviction logic from destroying
* our vma as we insert and bind.
*/
- if (likely(((++vma->flags ^ flags) & I915_VMA_BIND_MASK) == 0))
+ if (likely(((++vma->flags ^ flags) & I915_VMA_BIND_MASK) == 0)) {
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+ GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags));
return 0;
+ }
return __i915_vma_do_pin(vma, size, alignment, flags);
}
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 4612ffd555a7..41fd94e62d3c 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -85,6 +85,8 @@ intel_plane_duplicate_state(struct drm_plane *plane)
__drm_atomic_helper_plane_duplicate_state(plane, state);
+ intel_state->vma = NULL;
+
return state;
}
@@ -100,6 +102,24 @@ void
intel_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
+ struct i915_vma *vma;
+
+ vma = fetch_and_zero(&to_intel_plane_state(state)->vma);
+
+ /*
+ * FIXME: Normally intel_cleanup_plane_fb handles destruction of vma.
+ * We currently don't clear all planes during driver unload, so we have
+ * to be able to unpin vma here for now.
+ *
+ * Normally this can only happen during unload when kmscon is disabled
+ * and userspace doesn't attempt to set a framebuffer at all.
+ */
+ if (vma) {
+ mutex_lock(&plane->dev->struct_mutex);
+ intel_unpin_fb_vma(vma);
+ mutex_unlock(&plane->dev->struct_mutex);
+ }
+
drm_atomic_helper_plane_destroy_state(plane, state);
}
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 9cbb8d8363b4..0085bc745f6a 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -34,6 +34,10 @@
* low-power state and comes back to normal.
*/
+#define I915_CSR_GLK "i915/glk_dmc_ver1_01.bin"
+MODULE_FIRMWARE(I915_CSR_GLK);
+#define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 1)
+
#define I915_CSR_KBL "i915/kbl_dmc_ver1_01.bin"
MODULE_FIRMWARE(I915_CSR_KBL);
#define KBL_CSR_VERSION_REQUIRED CSR_VERSION(1, 1)
@@ -286,7 +290,9 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
csr->version = css_header->version;
- if (IS_KABYLAKE(dev_priv)) {
+ if (IS_GEMINILAKE(dev_priv)) {
+ required_version = GLK_CSR_VERSION_REQUIRED;
+ } else if (IS_KABYLAKE(dev_priv)) {
required_version = KBL_CSR_VERSION_REQUIRED;
} else if (IS_SKYLAKE(dev_priv)) {
required_version = SKL_CSR_VERSION_REQUIRED;
@@ -435,7 +441,9 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
if (!HAS_CSR(dev_priv))
return;
- if (IS_KABYLAKE(dev_priv))
+ if (IS_GEMINILAKE(dev_priv))
+ csr->fw_path = I915_CSR_GLK;
+ else if (IS_KABYLAKE(dev_priv))
csr->fw_path = I915_CSR_KBL;
else if (IS_SKYLAKE(dev_priv))
csr->fw_path = I915_CSR_SKL;
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index f642f6ded4ae..fcf81815daff 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -192,7 +192,7 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
hweight8(sseu->slice_mask) > 1;
sseu->has_subslice_pg =
- IS_BROXTON(dev_priv) && sseu_subslice_total(sseu) > 1;
+ IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1;
sseu->has_eu_pg = sseu->eu_per_subslice > 2;
if (IS_BROXTON(dev_priv)) {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e2150a64860c..b3e773c9f872 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2137,11 +2137,10 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
const struct drm_framebuffer *fb,
unsigned int rotation)
{
+ view->type = I915_GGTT_VIEW_NORMAL;
if (drm_rotation_90_or_270(rotation)) {
- *view = i915_ggtt_view_rotated;
- view->params.rotated = to_intel_framebuffer(fb)->rot_info;
- } else {
- *view = i915_ggtt_view_normal;
+ view->type = I915_GGTT_VIEW_ROTATED;
+ view->rotated = to_intel_framebuffer(fb)->rot_info;
}
}
@@ -2235,24 +2234,19 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
i915_vma_pin_fence(vma);
}
+ i915_vma_get(vma);
err:
intel_runtime_pm_put(dev_priv);
return vma;
}
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
+void intel_unpin_fb_vma(struct i915_vma *vma)
{
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct i915_ggtt_view view;
- struct i915_vma *vma;
-
- WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
-
- intel_fill_fb_ggtt_view(&view, fb, rotation);
- vma = i915_gem_object_to_ggtt(obj, &view);
+ lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
i915_vma_unpin_fence(vma);
i915_gem_object_unpin_from_display_plane(vma);
+ i915_vma_put(vma);
}
static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
@@ -2745,7 +2739,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_crtc *c;
- struct intel_crtc *i;
struct drm_i915_gem_object *obj;
struct drm_plane *primary = intel_crtc->base.primary;
struct drm_plane_state *plane_state = primary->state;
@@ -2770,20 +2763,20 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
* an fb with another CRTC instead
*/
for_each_crtc(dev, c) {
- i = to_intel_crtc(c);
+ struct intel_plane_state *state;
if (c == &intel_crtc->base)
continue;
- if (!i->active)
+ if (!to_intel_crtc(c)->active)
continue;
- fb = c->primary->fb;
- if (!fb)
+ state = to_intel_plane_state(c->primary->state);
+ if (!state->vma)
continue;
- obj = intel_fb_obj(fb);
- if (i915_gem_object_ggtt_offset(obj, NULL) == plane_config->base) {
+ if (intel_plane_ggtt_offset(state) == plane_config->base) {
+ fb = c->primary->fb;
drm_framebuffer_reference(fb);
goto valid_fb;
}
@@ -2796,7 +2789,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
* simplest solution is to just disable the primary plane now and
* pretend the BIOS never had it enabled.
*/
- to_intel_plane_state(plane_state)->base.visible = false;
+ plane_state->visible = false;
crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
intel_pre_disable_primary_noatomic(&intel_crtc->base);
intel_plane->disable_plane(primary, &intel_crtc->base);
@@ -2804,6 +2797,19 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
return;
valid_fb:
+ mutex_lock(&dev->struct_mutex);
+ intel_state->vma =
+ intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+ mutex_unlock(&dev->struct_mutex);
+ if (IS_ERR(intel_state->vma)) {
+ DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
+ intel_crtc->pipe, PTR_ERR(intel_state->vma));
+
+ intel_state->vma = NULL;
+ drm_framebuffer_unreference(fb);
+ return;
+ }
+
plane_state->src_x = 0;
plane_state->src_y = 0;
plane_state->src_w = fb->width << 16;
@@ -2966,6 +2972,9 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
unsigned int rotation = plane_state->base.rotation;
int ret;
+ if (!plane_state->base.visible)
+ return 0;
+
/* Rotate src coordinates to match rotated GTT view */
if (drm_rotation_90_or_270(rotation))
drm_rect_rotate(&plane_state->base.src,
@@ -3096,13 +3105,13 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
if (INTEL_GEN(dev_priv) >= 4) {
I915_WRITE(DSPSURF(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
I915_WRITE(DSPLINOFF(plane), linear_offset);
} else {
I915_WRITE(DSPADDR(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
}
POSTING_READ(reg);
@@ -3199,7 +3208,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
I915_WRITE(DSPSURF(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
@@ -3222,23 +3231,6 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
}
}
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb,
- unsigned int rotation)
-{
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct i915_ggtt_view view;
- struct i915_vma *vma;
-
- intel_fill_fb_ggtt_view(&view, fb, rotation);
-
- vma = i915_gem_object_to_ggtt(obj, &view);
- if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
- view.type))
- return -1;
-
- return i915_ggtt_offset(vma);
-}
-
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
{
struct drm_device *dev = intel_crtc->base.dev;
@@ -3434,7 +3426,7 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
}
I915_WRITE(PLANE_SURF(pipe, plane_id),
- intel_fb_gtt_offset(fb, rotation) + surf_addr);
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
POSTING_READ(PLANE_SURF(pipe, plane_id));
}
@@ -3558,23 +3550,19 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
state = drm_atomic_helper_duplicate_state(dev, ctx);
if (IS_ERR(state)) {
ret = PTR_ERR(state);
- state = NULL;
DRM_ERROR("Duplicating state failed with %i\n", ret);
- goto err;
+ return;
}
ret = drm_atomic_helper_disable_all(dev, ctx);
if (ret) {
DRM_ERROR("Suspending crtc's failed with %i\n", ret);
- goto err;
+ drm_atomic_state_put(state);
+ return;
}
dev_priv->modeset_restore_state = state;
state->acquire_ctx = ctx;
- return;
-
-err:
- drm_atomic_state_put(state);
}
void intel_finish_reset(struct drm_i915_private *dev_priv)
@@ -6883,13 +6871,13 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
if (!intel_crtc->active)
return;
- if (to_intel_plane_state(crtc->primary->state)->base.visible) {
+ if (crtc->primary->state->visible) {
WARN_ON(intel_crtc->flip_work);
intel_pre_disable_primary_noatomic(crtc);
intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
- to_intel_plane_state(crtc->primary->state)->base.visible = false;
+ crtc->primary->state->visible = false;
}
state = drm_atomic_state_alloc(crtc->dev);
@@ -8403,7 +8391,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
mode->type = DRM_MODE_TYPE_DRIVER;
mode->clock = pipe_config->base.adjusted_mode.crtc_clock;
- mode->flags |= pipe_config->base.adjusted_mode.flags;
mode->hsync = drm_mode_hsync(mode);
mode->vrefresh = drm_mode_vrefresh(mode);
@@ -11105,7 +11092,7 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state,
return PTR_ERR(plane_state);
if (mode)
- drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
+ drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
else
hdisplay = vdisplay = 0;
@@ -11288,6 +11275,7 @@ found:
}
old->restore_state = restore_state;
+ drm_atomic_state_put(state);
/* let the connector get through one full cycle before testing */
intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
@@ -11567,7 +11555,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
flush_work(&work->mmio_work);
mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
+ intel_unpin_fb_vma(work->old_vma);
i915_gem_object_put(work->pending_flip_obj);
mutex_unlock(&dev->struct_mutex);
@@ -12277,8 +12265,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
goto cleanup_pending;
}
- work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
- work->gtt_offset += intel_crtc->dspaddr_offset;
+ work->old_vma = to_intel_plane_state(primary->state)->vma;
+ to_intel_plane_state(primary->state)->vma = vma;
+
+ work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset;
work->rotation = crtc->primary->state->rotation;
/*
@@ -12333,7 +12323,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
cleanup_request:
i915_add_request_no_flush(request);
cleanup_unpin:
- intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
+ to_intel_plane_state(primary->state)->vma = work->old_vma;
+ intel_unpin_fb_vma(vma);
cleanup_pending:
atomic_dec(&intel_crtc->unpin_work_count);
unlock:
@@ -12463,7 +12454,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
}
was_visible = old_plane_state->base.visible;
- visible = to_intel_plane_state(plane_state)->base.visible;
+ visible = plane_state->visible;
if (!was_crtc_enabled && WARN_ON(was_visible))
was_visible = false;
@@ -12479,7 +12470,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
* only combine the results from all planes in the current place?
*/
if (!is_crtc_enabled)
- to_intel_plane_state(plane_state)->base.visible = visible = false;
+ plane_state->visible = visible = false;
if (!was_visible && !visible)
return 0;
@@ -12990,7 +12981,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
* computation to clearly distinguish it from the adjusted mode, which
* can be changed by the connectors in the below retry loop.
*/
- drm_crtc_get_hv_timing(&pipe_config->base.mode,
+ drm_mode_get_hv_timing(&pipe_config->base.mode,
&pipe_config->pipe_src_w,
&pipe_config->pipe_src_h);
@@ -14737,6 +14728,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.page_flip = intel_crtc_page_flip,
.atomic_duplicate_state = intel_crtc_duplicate_state,
.atomic_destroy_state = intel_crtc_destroy_state,
+ .set_crc_source = intel_crtc_set_crc_source,
};
/**
@@ -14833,6 +14825,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
DRM_DEBUG_KMS("failed to pin object\n");
return PTR_ERR(vma);
}
+
+ to_intel_plane_state(new_state)->vma = vma;
}
return 0;
@@ -14851,19 +14845,12 @@ void
intel_cleanup_plane_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- struct drm_i915_private *dev_priv = to_i915(plane->dev);
- struct intel_plane_state *old_intel_state;
- struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
- struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
-
- old_intel_state = to_intel_plane_state(old_state);
-
- if (!obj && !old_obj)
- return;
+ struct i915_vma *vma;
- if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
- !INTEL_INFO(dev_priv)->cursor_needs_physical))
- intel_unpin_fb_obj(old_state->fb, old_state->rotation);
+ /* Should only be called after a successful intel_prepare_plane_fb()! */
+ vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma);
+ if (vma)
+ intel_unpin_fb_vma(vma);
}
int
@@ -15015,6 +15002,7 @@ intel_legacy_cursor_update(struct drm_plane *plane,
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_framebuffer *old_fb;
struct drm_crtc_state *crtc_state = crtc->state;
+ struct i915_vma *old_vma;
/*
* When crtc is inactive or there is a modeset pending,
@@ -15086,9 +15074,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
ret = PTR_ERR(vma);
goto out_unlock;
}
+
+ to_intel_plane_state(new_plane_state)->vma = vma;
}
old_fb = old_plane_state->fb;
+ old_vma = to_intel_plane_state(old_plane_state)->vma;
i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb),
intel_plane->frontbuffer_bit);
@@ -15098,6 +15089,7 @@ intel_legacy_cursor_update(struct drm_plane *plane,
*to_intel_plane_state(old_plane_state) = *to_intel_plane_state(new_plane_state);
new_plane_state->fence = NULL;
new_plane_state->fb = old_fb;
+ to_intel_plane_state(new_plane_state)->vma = old_vma;
intel_plane->update_plane(plane,
to_intel_crtc_state(crtc->state),
@@ -15336,7 +15328,7 @@ intel_update_cursor_plane(struct drm_plane *plane,
if (!obj)
addr = 0;
else if (!INTEL_INFO(dev_priv)->cursor_needs_physical)
- addr = i915_gem_object_ggtt_offset(obj, NULL);
+ addr = intel_plane_ggtt_offset(state);
else
addr = obj->phys_handle->busaddr;
@@ -16840,7 +16832,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
* Temporarily change the plane mapping and disable everything
* ... */
plane = crtc->plane;
- to_intel_plane_state(crtc->base.primary->state)->base.visible = true;
+ crtc->base.primary->state->visible = true;
crtc->plane = !plane;
intel_crtc_disable_noatomic(&crtc->base);
crtc->plane = plane;
@@ -16992,7 +16984,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
dev_priv->active_crtcs = 0;
for_each_intel_crtc(dev, crtc) {
- struct intel_crtc_state *crtc_state = crtc->config;
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
__drm_atomic_helper_crtc_destroy_state(&crtc_state->base);
memset(crtc_state, 0, sizeof(*crtc_state));
@@ -17011,7 +17004,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n",
crtc->base.base.id, crtc->base.name,
- enableddisabled(crtc->active));
+ enableddisabled(crtc_state->base.active));
}
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
@@ -17021,7 +17014,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
&pll->state.hw_state);
pll->state.crtc_mask = 0;
for_each_intel_crtc(dev, crtc) {
- if (crtc->active && crtc->config->shared_dpll == pll)
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+
+ if (crtc_state->base.active &&
+ crtc_state->shared_dpll == pll)
pll->state.crtc_mask |= 1 << crtc->pipe;
}
pll->active_mask = pll->state.crtc_mask;
@@ -17034,11 +17031,14 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
pipe = 0;
if (encoder->get_hw_state(encoder, &pipe)) {
+ struct intel_crtc_state *crtc_state;
+
crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+ crtc_state = to_intel_crtc_state(crtc->base.state);
encoder->base.crtc = &crtc->base;
- crtc->config->output_types |= 1 << encoder->type;
- encoder->get_config(encoder, crtc->config);
+ crtc_state->output_types |= 1 << encoder->type;
+ encoder->get_config(encoder, crtc_state);
} else {
encoder->base.crtc = NULL;
}
@@ -17079,14 +17079,16 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
}
for_each_intel_crtc(dev, crtc) {
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
int pixclk = 0;
- crtc->base.hwmode = crtc->config->base.adjusted_mode;
+ crtc->base.hwmode = crtc_state->base.adjusted_mode;
memset(&crtc->base.mode, 0, sizeof(crtc->base.mode));
- if (crtc->base.state->active) {
- intel_mode_from_pipe_config(&crtc->base.mode, crtc->config);
- intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config);
+ if (crtc_state->base.active) {
+ intel_mode_from_pipe_config(&crtc->base.mode, crtc_state);
+ intel_mode_from_pipe_config(&crtc_state->base.adjusted_mode, crtc_state);
WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode));
/*
@@ -17098,17 +17100,17 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
* set a flag to indicate that a full recalculation is
* needed on the next commit.
*/
- crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED;
+ crtc_state->base.mode.private_flags = I915_MODE_FLAG_INHERITED;
if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
- pixclk = ilk_pipe_pixel_rate(crtc->config);
+ pixclk = ilk_pipe_pixel_rate(crtc_state);
else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- pixclk = crtc->config->base.adjusted_mode.crtc_clock;
+ pixclk = crtc_state->base.adjusted_mode.crtc_clock;
else
WARN_ON(dev_priv->display.modeset_calc_cdclk);
/* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
- if (IS_BROADWELL(dev_priv) && crtc->config->ips_enabled)
+ if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
pixclk = DIV_ROUND_UP(pixclk * 100, 95);
drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
@@ -17117,7 +17119,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
dev_priv->min_pixclk[crtc->pipe] = pixclk;
- intel_pipe_config_sanity_check(dev_priv, crtc->config);
+ intel_pipe_config_sanity_check(dev_priv, crtc_state);
}
}
@@ -17218,47 +17220,19 @@ void intel_display_resume(struct drm_device *dev)
if (ret)
DRM_ERROR("Restoring old state failed with %i\n", ret);
- drm_atomic_state_put(state);
+ if (state)
+ drm_atomic_state_put(state);
}
void intel_modeset_gem_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = to_i915(dev);
- struct drm_crtc *c;
- struct drm_i915_gem_object *obj;
intel_init_gt_powersave(dev_priv);
intel_modeset_init_hw(dev);
intel_setup_overlay(dev_priv);
-
- /*
- * Make sure any fbs we allocated at startup are properly
- * pinned & fenced. When we do the allocation it's too early
- * for this.
- */
- for_each_crtc(dev, c) {
- struct i915_vma *vma;
-
- obj = intel_fb_obj(c->primary->fb);
- if (obj == NULL)
- continue;
-
- mutex_lock(&dev->struct_mutex);
- vma = intel_pin_and_fence_fb_obj(c->primary->fb,
- c->primary->state->rotation);
- mutex_unlock(&dev->struct_mutex);
- if (IS_ERR(vma)) {
- DRM_ERROR("failed to pin boot fb on pipe %d\n",
- to_intel_crtc(c)->pipe);
- drm_framebuffer_unreference(c->primary->fb);
- c->primary->fb = NULL;
- c->primary->crtc = c->primary->state->crtc = NULL;
- update_state_fb(c->primary);
- c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
- }
- }
}
int intel_connector_register(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index fb12896bafee..3d8ac8aa7214 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1713,7 +1713,9 @@ found:
* VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
*/
pipe_config->limited_color_range =
- bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1;
+ bpp != 18 &&
+ drm_default_rgb_quant_range(adjusted_mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED;
} else {
pipe_config->limited_color_range =
intel_dp->limited_color_range;
@@ -3042,6 +3044,32 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_
DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
}
+static bool intel_dp_get_y_cord_status(struct intel_dp *intel_dp)
+{
+ uint8_t psr_caps = 0;
+
+ drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_CAPS, &psr_caps);
+ return psr_caps & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
+}
+
+static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
+{
+ uint8_t dprx = 0;
+
+ drm_dp_dpcd_readb(&intel_dp->aux,
+ DP_DPRX_FEATURE_ENUMERATION_LIST,
+ &dprx);
+ return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
+}
+
+static bool intel_dp_get_alpm_status(struct intel_dp *intel_dp)
+{
+ uint8_t alpm_caps = 0;
+
+ drm_dp_dpcd_readb(&intel_dp->aux, DP_RECEIVER_ALPM_CAP, &alpm_caps);
+ return alpm_caps & DP_ALPM_CAP;
+}
+
/* These are source-specific values. */
uint8_t
intel_dp_voltage_max(struct intel_dp *intel_dp)
@@ -3412,7 +3440,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp)
if (HAS_DDI(dev_priv)) {
signal_levels = ddi_signal_levels(intel_dp);
- if (IS_BROXTON(dev_priv))
+ if (IS_GEN9_LP(dev_priv))
signal_levels = 0;
else
mask = DDI_BUF_EMP_MASK;
@@ -3620,6 +3648,16 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
dev_priv->psr.psr2_support = dev_priv->psr.aux_frame_sync;
DRM_DEBUG_KMS("PSR2 %s on sink",
dev_priv->psr.psr2_support ? "supported" : "not supported");
+
+ if (dev_priv->psr.psr2_support) {
+ dev_priv->psr.y_cord_support =
+ intel_dp_get_y_cord_status(intel_dp);
+ dev_priv->psr.colorimetry_support =
+ intel_dp_get_colorimetry_status(intel_dp);
+ dev_priv->psr.alpm =
+ intel_dp_get_alpm_status(intel_dp);
+ }
+
}
/* Read the eDP Display control capabilities registers */
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 205fe4748ec5..38e3ca2f6f18 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -587,7 +587,8 @@ intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_ba
/* create encoders */
intel_dp_create_fake_mst_encoders(intel_dig_port);
- ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev->dev, &intel_dp->aux, 16, 3, conn_base_id);
+ ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
+ &intel_dp->aux, 16, 3, conn_base_id);
if (ret) {
intel_dp->can_mst = false;
return ret;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6b02dac6ea26..0cec0013ace0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -376,6 +376,7 @@ struct intel_atomic_state {
struct intel_plane_state {
struct drm_plane_state base;
struct drm_rect clip;
+ struct i915_vma *vma;
struct {
u32 offset;
@@ -1067,6 +1068,7 @@ struct intel_flip_work {
struct work_struct mmio_work;
struct drm_crtc *crtc;
+ struct i915_vma *old_vma;
struct drm_framebuffer *old_fb;
struct drm_i915_gem_object *pending_flip_obj;
struct drm_pending_vblank_event *event;
@@ -1302,7 +1304,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx);
struct i915_vma *
intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
+void intel_unpin_fb_vma(struct i915_vma *vma);
struct drm_framebuffer *
__intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
@@ -1391,7 +1393,10 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
+static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
+{
+ return i915_ggtt_offset(state->vma);
+}
u32 skl_plane_ctl_format(uint32_t pixel_format);
u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
@@ -1880,5 +1885,11 @@ void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
/* intel_pipe_crc.c */
int intel_pipe_crc_create(struct drm_minor *minor);
void intel_pipe_crc_cleanup(struct drm_minor *minor);
+#ifdef CONFIG_DEBUG_FS
+int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
+ size_t *values_cnt);
+#else
+#define intel_crtc_set_crc_source NULL
+#endif
extern const struct file_operations i915_display_crc_ctl_fops;
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index 97bbbc3d6aa8..371acf109e34 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -264,7 +264,7 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, int size)
return PTR_ERR(obj);
}
- vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto err_unref;
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index 26a81a9e9c1d..89fe5c8464df 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -173,7 +173,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv)
if (IS_I945GM(dev_priv))
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
- fbc_ctl |= params->fb.fence_reg;
+ fbc_ctl |= params->vma->fence->id;
I915_WRITE(FBC_CONTROL, fbc_ctl);
}
@@ -193,8 +193,8 @@ static void g4x_fbc_activate(struct drm_i915_private *dev_priv)
else
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
- dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg;
+ if (params->vma->fence) {
+ dpfc_ctl |= DPFC_CTL_FENCE_EN | params->vma->fence->id;
I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
} else {
I915_WRITE(DPFC_FENCE_YOFF, 0);
@@ -251,13 +251,14 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
break;
}
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+ if (params->vma->fence) {
dpfc_ctl |= DPFC_CTL_FENCE_EN;
if (IS_GEN5(dev_priv))
- dpfc_ctl |= params->fb.fence_reg;
+ dpfc_ctl |= params->vma->fence->id;
if (IS_GEN6(dev_priv)) {
I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+ SNB_CPU_FENCE_ENABLE |
+ params->vma->fence->id);
I915_WRITE(DPFC_CPU_FENCE_OFFSET,
params->crtc.fence_y_offset);
}
@@ -269,7 +270,8 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
}
I915_WRITE(ILK_DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
- I915_WRITE(ILK_FBC_RT_BASE, params->fb.ggtt_offset | ILK_FBC_RT_VALID);
+ I915_WRITE(ILK_FBC_RT_BASE,
+ i915_ggtt_offset(params->vma) | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
@@ -319,10 +321,11 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
break;
}
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+ if (params->vma->fence) {
dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+ SNB_CPU_FENCE_ENABLE |
+ params->vma->fence->id);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
} else {
I915_WRITE(SNB_DPFC_CTL_SA,0);
@@ -727,14 +730,6 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
return effective_w <= max_w && effective_h <= max_h;
}
-/* XXX replace me when we have VMA tracking for intel_plane_state */
-static int get_fence_id(struct drm_framebuffer *fb)
-{
- struct i915_vma *vma = i915_gem_object_to_ggtt(intel_fb_obj(fb), NULL);
-
- return vma && vma->fence ? vma->fence->id : I915_FENCE_REG_NONE;
-}
-
static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
@@ -743,7 +738,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
struct intel_fbc *fbc = &dev_priv->fbc;
struct intel_fbc_state_cache *cache = &fbc->state_cache;
struct drm_framebuffer *fb = plane_state->base.fb;
- struct drm_i915_gem_object *obj;
+
+ cache->vma = NULL;
cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
@@ -758,16 +754,10 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
if (!cache->plane.visible)
return;
- obj = intel_fb_obj(fb);
-
- /* FIXME: We lack the proper locking here, so only run this on the
- * platforms that need. */
- if (IS_GEN(dev_priv, 5, 6))
- cache->fb.ilk_ggtt_offset = i915_gem_object_ggtt_offset(obj, NULL);
cache->fb.format = fb->format;
cache->fb.stride = fb->pitches[0];
- cache->fb.fence_reg = get_fence_id(fb);
- cache->fb.tiling_mode = i915_gem_object_get_tiling(obj);
+
+ cache->vma = plane_state->vma;
}
static bool intel_fbc_can_activate(struct intel_crtc *crtc)
@@ -784,7 +774,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
return false;
}
- if (!cache->plane.visible) {
+ if (!cache->vma) {
fbc->no_fbc_reason = "primary plane not visible";
return false;
}
@@ -807,8 +797,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
* so have no fence associated with it) due to aperture constaints
* at the time of pinning.
*/
- if (cache->fb.tiling_mode != I915_TILING_X ||
- cache->fb.fence_reg == I915_FENCE_REG_NONE) {
+ if (!cache->vma->fence) {
fbc->no_fbc_reason = "framebuffer not tiled or fenced";
return false;
}
@@ -888,17 +877,16 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc,
* zero. */
memset(params, 0, sizeof(*params));
+ params->vma = cache->vma;
+
params->crtc.pipe = crtc->pipe;
params->crtc.plane = crtc->plane;
params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc);
params->fb.format = cache->fb.format;
params->fb.stride = cache->fb.stride;
- params->fb.fence_reg = cache->fb.fence_reg;
params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
-
- params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset;
}
static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
@@ -1296,7 +1284,7 @@ void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv)
for_each_intel_crtc(&dev_priv->drm, crtc)
if (intel_crtc_active(crtc) &&
- to_intel_plane_state(crtc->base.primary->state)->base.visible)
+ crtc->base.primary->state->visible)
dev_priv->fbc.visible_pipes_mask |= (1 << crtc->pipe);
}
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index bdefa61f2e60..e0d9e72cf3d1 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -284,7 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
out_destroy_fbi:
drm_fb_helper_release_fbi(helper);
out_unpin:
- intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+ intel_unpin_fb_vma(vma);
out_unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -549,7 +549,7 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
if (ifbdev->fb) {
mutex_lock(&ifbdev->helper.dev->struct_mutex);
- intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+ intel_unpin_fb_vma(ifbdev->vma);
mutex_unlock(&ifbdev->helper.dev->struct_mutex);
drm_framebuffer_remove(&ifbdev->fb->base);
@@ -742,6 +742,9 @@ void intel_fbdev_initial_config_async(struct drm_device *dev)
{
struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
+ if (!ifbdev)
+ return;
+
ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev);
}
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 3202b32b5638..25691f0e4c50 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -145,7 +145,7 @@
* The GuC firmware layout looks like this:
*
* +-------------------------------+
- * | guc_css_header |
+ * | uc_css_header |
* | |
* | contains major/minor version |
* +-------------------------------+
@@ -172,9 +172,16 @@
* 3. Length info of each component can be found in header, in dwords.
* 4. Modulus and exponent key are not required by driver. They may not appear
* in fw. So driver will load a truncated firmware in this case.
+ *
+ * HuC firmware layout is same as GuC firmware.
+ *
+ * HuC firmware css header is different. However, the only difference is where
+ * the version information is saved. The uc_css_header is unified to support
+ * both. Driver should get HuC version from uc_css_header.huc_sw_version, while
+ * uc_css_header.guc_sw_version for GuC.
*/
-struct guc_css_header {
+struct uc_css_header {
uint32_t module_type;
/* header_size includes all non-uCode bits, including css_header, rsa
* key, modulus key and exponent data. */
@@ -205,8 +212,16 @@ struct guc_css_header {
char username[8];
char buildnumber[12];
- uint32_t device_id;
- uint32_t guc_sw_version;
+ union {
+ struct {
+ uint32_t branch_client_version;
+ uint32_t sw_version;
+ } guc;
+ struct {
+ uint32_t sw_version;
+ uint32_t reserved;
+ } huc;
+ };
uint32_t prod_preprod_fw;
uint32_t reserved[12];
uint32_t header_info;
@@ -490,6 +505,7 @@ enum intel_guc_action {
INTEL_GUC_ACTION_ENTER_S_STATE = 0x501,
INTEL_GUC_ACTION_EXIT_S_STATE = 0x502,
INTEL_GUC_ACTION_SLPC_REQUEST = 0x3003,
+ INTEL_GUC_ACTION_AUTHENTICATE_HUC = 0x4000,
INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING = 0x0E000,
INTEL_GUC_ACTION_LIMIT
};
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 35d5690f47a2..2f1cf9aea04e 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -51,12 +51,6 @@
* 512K. In order to exclude 0-512K address space from GGTT, all gfx objects
* used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
*
- * Firmware log:
- * Firmware log is enabled by setting i915.guc_log_level to non-negative level.
- * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
- * i915_guc_load_status will print out firmware loading status and scratch
- * registers value.
- *
*/
#define SKL_FW_MAJOR 6
@@ -81,16 +75,16 @@ MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
MODULE_FIRMWARE(I915_KBL_GUC_UCODE);
/* User-friendly representation of an enum */
-const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
+const char *intel_uc_fw_status_repr(enum intel_uc_fw_status status)
{
switch (status) {
- case GUC_FIRMWARE_FAIL:
+ case INTEL_UC_FIRMWARE_FAIL:
return "FAIL";
- case GUC_FIRMWARE_NONE:
+ case INTEL_UC_FIRMWARE_NONE:
return "NONE";
- case GUC_FIRMWARE_PENDING:
+ case INTEL_UC_FIRMWARE_PENDING:
return "PENDING";
- case GUC_FIRMWARE_SUCCESS:
+ case INTEL_UC_FIRMWARE_SUCCESS:
return "SUCCESS";
default:
return "UNKNOWN!";
@@ -278,7 +272,7 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv,
struct i915_vma *vma)
{
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
unsigned long offset;
struct sg_table *sg = vma->pages;
u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
@@ -334,12 +328,12 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv,
return ret;
}
-static u32 guc_wopcm_size(struct drm_i915_private *dev_priv)
+u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv)
{
u32 wopcm_size = GUC_WOPCM_TOP;
/* On BXT, the top of WOPCM is reserved for RC6 context */
- if (IS_BROXTON(dev_priv))
+ if (IS_GEN9_LP(dev_priv))
wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED;
return wopcm_size;
@@ -350,29 +344,27 @@ static u32 guc_wopcm_size(struct drm_i915_private *dev_priv)
*/
static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
{
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
struct i915_vma *vma;
int ret;
- ret = i915_gem_object_set_to_gtt_domain(guc_fw->guc_fw_obj, false);
+ ret = i915_gem_object_set_to_gtt_domain(guc_fw->obj, false);
if (ret) {
DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
return ret;
}
- vma = i915_gem_object_ggtt_pin(guc_fw->guc_fw_obj, NULL, 0, 0, 0);
+ vma = i915_gem_object_ggtt_pin(guc_fw->obj, NULL, 0, 0,
+ PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
if (IS_ERR(vma)) {
DRM_DEBUG_DRIVER("pin failed %d\n", (int)PTR_ERR(vma));
return PTR_ERR(vma);
}
- /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
- I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
-
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
/* init WOPCM */
- I915_WRITE(GUC_WOPCM_SIZE, guc_wopcm_size(dev_priv));
+ I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv));
I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE);
/* Enable MIA caching. GuC clock gating is disabled. */
@@ -388,7 +380,7 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
- if (IS_BROXTON(dev_priv))
+ if (IS_GEN9_LP(dev_priv))
I915_WRITE(GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
else
I915_WRITE(GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
@@ -450,14 +442,14 @@ static int guc_hw_reset(struct drm_i915_private *dev_priv)
*/
int intel_guc_setup(struct drm_i915_private *dev_priv)
{
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
- const char *fw_path = guc_fw->guc_fw_path;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
+ const char *fw_path = guc_fw->path;
int retries, ret, err;
DRM_DEBUG_DRIVER("GuC fw status: path %s, fetch %s, load %s\n",
fw_path,
- intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
- intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ intel_uc_fw_status_repr(guc_fw->fetch_status),
+ intel_uc_fw_status_repr(guc_fw->load_status));
/* Loading forbidden, or no firmware to load? */
if (!i915.enable_guc_loading) {
@@ -475,10 +467,10 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
}
/* Fetch failed, or already fetched but failed to load? */
- if (guc_fw->guc_fw_fetch_status != GUC_FIRMWARE_SUCCESS) {
+ if (guc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS) {
err = -EIO;
goto fail;
- } else if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL) {
+ } else if (guc_fw->load_status == INTEL_UC_FIRMWARE_FAIL) {
err = -ENOEXEC;
goto fail;
}
@@ -486,11 +478,14 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
guc_interrupts_release(dev_priv);
gen9_reset_guc_interrupts(dev_priv);
- guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
+ /* We need to notify the guc whenever we change the GGTT */
+ i915_ggtt_enable_guc(dev_priv);
+
+ guc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
- intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
- intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ intel_uc_fw_status_repr(guc_fw->fetch_status),
+ intel_uc_fw_status_repr(guc_fw->load_status));
err = i915_guc_submission_init(dev_priv);
if (err)
@@ -511,6 +506,7 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
if (err)
goto fail;
+ intel_huc_load(dev_priv);
err = guc_ucode_xfer(dev_priv);
if (!err)
break;
@@ -522,11 +518,13 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
"retry %d more time(s)\n", err, retries);
}
- guc_fw->guc_fw_load_status = GUC_FIRMWARE_SUCCESS;
+ guc_fw->load_status = INTEL_UC_FIRMWARE_SUCCESS;
DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
- intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
- intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ intel_uc_fw_status_repr(guc_fw->fetch_status),
+ intel_uc_fw_status_repr(guc_fw->load_status));
+
+ intel_guc_auth_huc(dev_priv);
if (i915.enable_guc_submission) {
if (i915.guc_log_level >= 0)
@@ -541,12 +539,13 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
return 0;
fail:
- if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING)
- guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL;
+ if (guc_fw->load_status == INTEL_UC_FIRMWARE_PENDING)
+ guc_fw->load_status = INTEL_UC_FIRMWARE_FAIL;
guc_interrupts_release(dev_priv);
i915_guc_submission_disable(dev_priv);
i915_guc_submission_fini(dev_priv);
+ i915_ggtt_disable_guc(dev_priv);
/*
* We've failed to load the firmware :(
@@ -587,93 +586,108 @@ fail:
return ret;
}
-static void guc_fw_fetch(struct drm_i915_private *dev_priv,
- struct intel_guc_fw *guc_fw)
+void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
+ struct intel_uc_fw *uc_fw)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
struct drm_i915_gem_object *obj;
const struct firmware *fw = NULL;
- struct guc_css_header *css;
+ struct uc_css_header *css;
size_t size;
int err;
- DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
- intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
+ DRM_DEBUG_DRIVER("before requesting firmware: uC fw fetch status %s\n",
+ intel_uc_fw_status_repr(uc_fw->fetch_status));
- err = request_firmware(&fw, guc_fw->guc_fw_path, &pdev->dev);
+ err = request_firmware(&fw, uc_fw->path, &pdev->dev);
if (err)
goto fail;
if (!fw)
goto fail;
- DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
- guc_fw->guc_fw_path, fw);
+ DRM_DEBUG_DRIVER("fetch uC fw from %s succeeded, fw %p\n",
+ uc_fw->path, fw);
/* Check the size of the blob before examining buffer contents */
- if (fw->size < sizeof(struct guc_css_header)) {
+ if (fw->size < sizeof(struct uc_css_header)) {
DRM_NOTE("Firmware header is missing\n");
goto fail;
}
- css = (struct guc_css_header *)fw->data;
+ css = (struct uc_css_header *)fw->data;
/* Firmware bits always start from header */
- guc_fw->header_offset = 0;
- guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
+ uc_fw->header_offset = 0;
+ uc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
- if (guc_fw->header_size != sizeof(struct guc_css_header)) {
+ if (uc_fw->header_size != sizeof(struct uc_css_header)) {
DRM_NOTE("CSS header definition mismatch\n");
goto fail;
}
/* then, uCode */
- guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size;
- guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
+ uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
+ uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
/* now RSA */
if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
DRM_NOTE("RSA key size is bad\n");
goto fail;
}
- guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
- guc_fw->rsa_size = css->key_size_dw * sizeof(u32);
+ uc_fw->rsa_offset = uc_fw->ucode_offset + uc_fw->ucode_size;
+ uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
/* At least, it should have header, uCode and RSA. Size of all three. */
- size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
+ size = uc_fw->header_size + uc_fw->ucode_size + uc_fw->rsa_size;
if (fw->size < size) {
DRM_NOTE("Missing firmware components\n");
goto fail;
}
- /* Header and uCode will be loaded to WOPCM. Size of the two. */
- size = guc_fw->header_size + guc_fw->ucode_size;
- if (size > guc_wopcm_size(dev_priv)) {
- DRM_NOTE("Firmware is too large to fit in WOPCM\n");
- goto fail;
- }
-
/*
* The GuC firmware image has the version number embedded at a well-known
* offset within the firmware blob; note that major / minor version are
* TWO bytes each (i.e. u16), although all pointers and offsets are defined
* in terms of bytes (u8).
*/
- guc_fw->guc_fw_major_found = css->guc_sw_version >> 16;
- guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF;
-
- if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
- guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
- DRM_NOTE("GuC firmware version %d.%d, required %d.%d\n",
- guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
- guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+ switch (uc_fw->fw) {
+ case INTEL_UC_FW_TYPE_GUC:
+ /* Header and uCode will be loaded to WOPCM. Size of the two. */
+ size = uc_fw->header_size + uc_fw->ucode_size;
+
+ /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
+ if (size > intel_guc_wopcm_size(dev_priv)) {
+ DRM_ERROR("Firmware is too large to fit in WOPCM\n");
+ goto fail;
+ }
+ uc_fw->major_ver_found = css->guc.sw_version >> 16;
+ uc_fw->minor_ver_found = css->guc.sw_version & 0xFFFF;
+ break;
+
+ case INTEL_UC_FW_TYPE_HUC:
+ uc_fw->major_ver_found = css->huc.sw_version >> 16;
+ uc_fw->minor_ver_found = css->huc.sw_version & 0xFFFF;
+ break;
+
+ default:
+ DRM_ERROR("Unknown firmware type %d\n", uc_fw->fw);
+ err = -ENOEXEC;
+ goto fail;
+ }
+
+ if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
+ uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
+ DRM_NOTE("uC firmware version %d.%d, required %d.%d\n",
+ uc_fw->major_ver_found, uc_fw->minor_ver_found,
+ uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
err = -ENOEXEC;
goto fail;
}
DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n",
- guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
- guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+ uc_fw->major_ver_found, uc_fw->minor_ver_found,
+ uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
mutex_lock(&dev_priv->drm.struct_mutex);
obj = i915_gem_object_create_from_data(dev_priv, fw->data, fw->size);
@@ -683,31 +697,31 @@ static void guc_fw_fetch(struct drm_i915_private *dev_priv,
goto fail;
}
- guc_fw->guc_fw_obj = obj;
- guc_fw->guc_fw_size = fw->size;
+ uc_fw->obj = obj;
+ uc_fw->size = fw->size;
- DRM_DEBUG_DRIVER("GuC fw fetch status SUCCESS, obj %p\n",
- guc_fw->guc_fw_obj);
+ DRM_DEBUG_DRIVER("uC fw fetch status SUCCESS, obj %p\n",
+ uc_fw->obj);
release_firmware(fw);
- guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_SUCCESS;
+ uc_fw->fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
return;
fail:
- DRM_WARN("Failed to fetch valid GuC firmware from %s (error %d)\n",
- guc_fw->guc_fw_path, err);
- DRM_DEBUG_DRIVER("GuC fw fetch status FAIL; err %d, fw %p, obj %p\n",
- err, fw, guc_fw->guc_fw_obj);
+ DRM_WARN("Failed to fetch valid uC firmware from %s (error %d)\n",
+ uc_fw->path, err);
+ DRM_DEBUG_DRIVER("uC fw fetch status FAIL; err %d, fw %p, obj %p\n",
+ err, fw, uc_fw->obj);
mutex_lock(&dev_priv->drm.struct_mutex);
- obj = guc_fw->guc_fw_obj;
+ obj = uc_fw->obj;
if (obj)
i915_gem_object_put(obj);
- guc_fw->guc_fw_obj = NULL;
+ uc_fw->obj = NULL;
mutex_unlock(&dev_priv->drm.struct_mutex);
release_firmware(fw); /* OK even if fw is NULL */
- guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL;
+ uc_fw->fetch_status = INTEL_UC_FIRMWARE_FAIL;
}
/**
@@ -721,7 +735,7 @@ fail:
*/
void intel_guc_init(struct drm_i915_private *dev_priv)
{
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
const char *fw_path;
if (!HAS_GUC(dev_priv)) {
@@ -739,23 +753,23 @@ void intel_guc_init(struct drm_i915_private *dev_priv)
fw_path = NULL;
} else if (IS_SKYLAKE(dev_priv)) {
fw_path = I915_SKL_GUC_UCODE;
- guc_fw->guc_fw_major_wanted = SKL_FW_MAJOR;
- guc_fw->guc_fw_minor_wanted = SKL_FW_MINOR;
+ guc_fw->major_ver_wanted = SKL_FW_MAJOR;
+ guc_fw->minor_ver_wanted = SKL_FW_MINOR;
} else if (IS_BROXTON(dev_priv)) {
fw_path = I915_BXT_GUC_UCODE;
- guc_fw->guc_fw_major_wanted = BXT_FW_MAJOR;
- guc_fw->guc_fw_minor_wanted = BXT_FW_MINOR;
+ guc_fw->major_ver_wanted = BXT_FW_MAJOR;
+ guc_fw->minor_ver_wanted = BXT_FW_MINOR;
} else if (IS_KABYLAKE(dev_priv)) {
fw_path = I915_KBL_GUC_UCODE;
- guc_fw->guc_fw_major_wanted = KBL_FW_MAJOR;
- guc_fw->guc_fw_minor_wanted = KBL_FW_MINOR;
+ guc_fw->major_ver_wanted = KBL_FW_MAJOR;
+ guc_fw->minor_ver_wanted = KBL_FW_MINOR;
} else {
fw_path = ""; /* unknown device */
}
- guc_fw->guc_fw_path = fw_path;
- guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
- guc_fw->guc_fw_load_status = GUC_FIRMWARE_NONE;
+ guc_fw->path = fw_path;
+ guc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
+ guc_fw->load_status = INTEL_UC_FIRMWARE_NONE;
/* Early (and silent) return if GuC loading is disabled */
if (!i915.enable_guc_loading)
@@ -765,9 +779,9 @@ void intel_guc_init(struct drm_i915_private *dev_priv)
if (*fw_path == '\0')
return;
- guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_PENDING;
+ guc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
DRM_DEBUG_DRIVER("GuC firmware pending, path %s\n", fw_path);
- guc_fw_fetch(dev_priv, guc_fw);
+ intel_uc_fw_fetch(dev_priv, guc_fw);
/* status must now be FAIL or SUCCESS */
}
@@ -777,17 +791,17 @@ void intel_guc_init(struct drm_i915_private *dev_priv)
*/
void intel_guc_fini(struct drm_i915_private *dev_priv)
{
- struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
mutex_lock(&dev_priv->drm.struct_mutex);
guc_interrupts_release(dev_priv);
i915_guc_submission_disable(dev_priv);
i915_guc_submission_fini(dev_priv);
- if (guc_fw->guc_fw_obj)
- i915_gem_object_put(guc_fw->guc_fw_obj);
- guc_fw->guc_fw_obj = NULL;
+ if (guc_fw->obj)
+ i915_gem_object_put(guc_fw->obj);
+ guc_fw->obj = NULL;
mutex_unlock(&dev_priv->drm.struct_mutex);
- guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
+ guc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
}
diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c
new file mode 100644
index 000000000000..5c0f9a49da0e
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_log.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright © 2014-2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/relay.h>
+#include "i915_drv.h"
+
+static void guc_log_capture_logs(struct intel_guc *guc);
+
+/**
+ * DOC: GuC firmware log
+ *
+ * Firmware log is enabled by setting i915.guc_log_level to non-negative level.
+ * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
+ * i915_guc_load_status will print out firmware loading status and scratch
+ * registers value.
+ *
+ */
+
+static int guc_log_flush_complete(struct intel_guc *guc)
+{
+ u32 action[] = {
+ INTEL_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE
+ };
+
+ return intel_guc_send(guc, action, ARRAY_SIZE(action));
+}
+
+static int guc_log_flush(struct intel_guc *guc)
+{
+ u32 action[] = {
+ INTEL_GUC_ACTION_FORCE_LOG_BUFFER_FLUSH,
+ 0
+ };
+
+ return intel_guc_send(guc, action, ARRAY_SIZE(action));
+}
+
+static int guc_log_control(struct intel_guc *guc, u32 control_val)
+{
+ u32 action[] = {
+ INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING,
+ control_val
+ };
+
+ return intel_guc_send(guc, action, ARRAY_SIZE(action));
+}
+
+
+/*
+ * Sub buffer switch callback. Called whenever relay has to switch to a new
+ * sub buffer, relay stays on the same sub buffer if 0 is returned.
+ */
+static int subbuf_start_callback(struct rchan_buf *buf,
+ void *subbuf,
+ void *prev_subbuf,
+ size_t prev_padding)
+{
+ /* Use no-overwrite mode by default, where relay will stop accepting
+ * new data if there are no empty sub buffers left.
+ * There is no strict synchronization enforced by relay between Consumer
+ * and Producer. In overwrite mode, there is a possibility of getting
+ * inconsistent/garbled data, the producer could be writing on to the
+ * same sub buffer from which Consumer is reading. This can't be avoided
+ * unless Consumer is fast enough and can always run in tandem with
+ * Producer.
+ */
+ if (relay_buf_full(buf))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * file_create() callback. Creates relay file in debugfs.
+ */
+static struct dentry *create_buf_file_callback(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ struct dentry *buf_file;
+
+ /* This to enable the use of a single buffer for the relay channel and
+ * correspondingly have a single file exposed to User, through which
+ * it can collect the logs in order without any post-processing.
+ * Need to set 'is_global' even if parent is NULL for early logging.
+ */
+ *is_global = 1;
+
+ if (!parent)
+ return NULL;
+
+ /* Not using the channel filename passed as an argument, since for each
+ * channel relay appends the corresponding CPU number to the filename
+ * passed in relay_open(). This should be fine as relay just needs a
+ * dentry of the file associated with the channel buffer and that file's
+ * name need not be same as the filename passed as an argument.
+ */
+ buf_file = debugfs_create_file("guc_log", mode,
+ parent, buf, &relay_file_operations);
+ return buf_file;
+}
+
+/*
+ * file_remove() default callback. Removes relay file in debugfs.
+ */
+static int remove_buf_file_callback(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+ return 0;
+}
+
+/* relay channel callbacks */
+static struct rchan_callbacks relay_callbacks = {
+ .subbuf_start = subbuf_start_callback,
+ .create_buf_file = create_buf_file_callback,
+ .remove_buf_file = remove_buf_file_callback,
+};
+
+static void guc_log_remove_relay_file(struct intel_guc *guc)
+{
+ relay_close(guc->log.relay_chan);
+}
+
+static int guc_log_create_relay_channel(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ struct rchan *guc_log_relay_chan;
+ size_t n_subbufs, subbuf_size;
+
+ /* Keep the size of sub buffers same as shared log buffer */
+ subbuf_size = guc->log.vma->obj->base.size;
+
+ /* Store up to 8 snapshots, which is large enough to buffer sufficient
+ * boot time logs and provides enough leeway to User, in terms of
+ * latency, for consuming the logs from relay. Also doesn't take
+ * up too much memory.
+ */
+ n_subbufs = 8;
+
+ guc_log_relay_chan = relay_open(NULL, NULL, subbuf_size,
+ n_subbufs, &relay_callbacks, dev_priv);
+ if (!guc_log_relay_chan) {
+ DRM_ERROR("Couldn't create relay chan for GuC logging\n");
+ return -ENOMEM;
+ }
+
+ GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size);
+ guc->log.relay_chan = guc_log_relay_chan;
+ return 0;
+}
+
+static int guc_log_create_relay_file(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ struct dentry *log_dir;
+ int ret;
+
+ /* For now create the log file in /sys/kernel/debug/dri/0 dir */
+ log_dir = dev_priv->drm.primary->debugfs_root;
+
+ /* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
+ * not mounted and so can't create the relay file.
+ * The relay API seems to fit well with debugfs only, for availing relay
+ * there are 3 requirements which can be met for debugfs file only in a
+ * straightforward/clean manner :-
+ * i) Need the associated dentry pointer of the file, while opening the
+ * relay channel.
+ * ii) Should be able to use 'relay_file_operations' fops for the file.
+ * iii) Set the 'i_private' field of file's inode to the pointer of
+ * relay channel buffer.
+ */
+ if (!log_dir) {
+ DRM_ERROR("Debugfs dir not available yet for GuC log file\n");
+ return -ENODEV;
+ }
+
+ ret = relay_late_setup_files(guc->log.relay_chan, "guc_log", log_dir);
+ if (ret) {
+ DRM_ERROR("Couldn't associate relay chan with file %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void guc_move_to_next_buf(struct intel_guc *guc)
+{
+ /* Make sure the updates made in the sub buffer are visible when
+ * Consumer sees the following update to offset inside the sub buffer.
+ */
+ smp_wmb();
+
+ /* All data has been written, so now move the offset of sub buffer. */
+ relay_reserve(guc->log.relay_chan, guc->log.vma->obj->base.size);
+
+ /* Switch to the next sub buffer */
+ relay_flush(guc->log.relay_chan);
+}
+
+static void *guc_get_write_buffer(struct intel_guc *guc)
+{
+ if (!guc->log.relay_chan)
+ return NULL;
+
+ /* Just get the base address of a new sub buffer and copy data into it
+ * ourselves. NULL will be returned in no-overwrite mode, if all sub
+ * buffers are full. Could have used the relay_write() to indirectly
+ * copy the data, but that would have been bit convoluted, as we need to
+ * write to only certain locations inside a sub buffer which cannot be
+ * done without using relay_reserve() along with relay_write(). So its
+ * better to use relay_reserve() alone.
+ */
+ return relay_reserve(guc->log.relay_chan, 0);
+}
+
+static bool guc_check_log_buf_overflow(struct intel_guc *guc,
+ enum guc_log_buffer_type type,
+ unsigned int full_cnt)
+{
+ unsigned int prev_full_cnt = guc->log.prev_overflow_count[type];
+ bool overflow = false;
+
+ if (full_cnt != prev_full_cnt) {
+ overflow = true;
+
+ guc->log.prev_overflow_count[type] = full_cnt;
+ guc->log.total_overflow_count[type] += full_cnt - prev_full_cnt;
+
+ if (full_cnt < prev_full_cnt) {
+ /* buffer_full_cnt is a 4 bit counter */
+ guc->log.total_overflow_count[type] += 16;
+ }
+ DRM_ERROR_RATELIMITED("GuC log buffer overflow\n");
+ }
+
+ return overflow;
+}
+
+static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
+{
+ switch (type) {
+ case GUC_ISR_LOG_BUFFER:
+ return (GUC_LOG_ISR_PAGES + 1) * PAGE_SIZE;
+ case GUC_DPC_LOG_BUFFER:
+ return (GUC_LOG_DPC_PAGES + 1) * PAGE_SIZE;
+ case GUC_CRASH_DUMP_LOG_BUFFER:
+ return (GUC_LOG_CRASH_PAGES + 1) * PAGE_SIZE;
+ default:
+ MISSING_CASE(type);
+ }
+
+ return 0;
+}
+
+static void guc_read_update_log_buffer(struct intel_guc *guc)
+{
+ unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt;
+ struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state;
+ struct guc_log_buffer_state log_buf_state_local;
+ enum guc_log_buffer_type type;
+ void *src_data, *dst_data;
+ bool new_overflow;
+
+ if (WARN_ON(!guc->log.buf_addr))
+ return;
+
+ /* Get the pointer to shared GuC log buffer */
+ log_buf_state = src_data = guc->log.buf_addr;
+
+ /* Get the pointer to local buffer to store the logs */
+ log_buf_snapshot_state = dst_data = guc_get_write_buffer(guc);
+
+ /* Actual logs are present from the 2nd page */
+ src_data += PAGE_SIZE;
+ dst_data += PAGE_SIZE;
+
+ for (type = GUC_ISR_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
+ /* Make a copy of the state structure, inside GuC log buffer
+ * (which is uncached mapped), on the stack to avoid reading
+ * from it multiple times.
+ */
+ memcpy(&log_buf_state_local, log_buf_state,
+ sizeof(struct guc_log_buffer_state));
+ buffer_size = guc_get_log_buffer_size(type);
+ read_offset = log_buf_state_local.read_ptr;
+ write_offset = log_buf_state_local.sampled_write_ptr;
+ full_cnt = log_buf_state_local.buffer_full_cnt;
+
+ /* Bookkeeping stuff */
+ guc->log.flush_count[type] += log_buf_state_local.flush_to_file;
+ new_overflow = guc_check_log_buf_overflow(guc, type, full_cnt);
+
+ /* Update the state of shared log buffer */
+ log_buf_state->read_ptr = write_offset;
+ log_buf_state->flush_to_file = 0;
+ log_buf_state++;
+
+ if (unlikely(!log_buf_snapshot_state))
+ continue;
+
+ /* First copy the state structure in snapshot buffer */
+ memcpy(log_buf_snapshot_state, &log_buf_state_local,
+ sizeof(struct guc_log_buffer_state));
+
+ /* The write pointer could have been updated by GuC firmware,
+ * after sending the flush interrupt to Host, for consistency
+ * set write pointer value to same value of sampled_write_ptr
+ * in the snapshot buffer.
+ */
+ log_buf_snapshot_state->write_ptr = write_offset;
+ log_buf_snapshot_state++;
+
+ /* Now copy the actual logs. */
+ if (unlikely(new_overflow)) {
+ /* copy the whole buffer in case of overflow */
+ read_offset = 0;
+ write_offset = buffer_size;
+ } else if (unlikely((read_offset > buffer_size) ||
+ (write_offset > buffer_size))) {
+ DRM_ERROR("invalid log buffer state\n");
+ /* copy whole buffer as offsets are unreliable */
+ read_offset = 0;
+ write_offset = buffer_size;
+ }
+
+ /* Just copy the newly written data */
+ if (read_offset > write_offset) {
+ i915_memcpy_from_wc(dst_data, src_data, write_offset);
+ bytes_to_copy = buffer_size - read_offset;
+ } else {
+ bytes_to_copy = write_offset - read_offset;
+ }
+ i915_memcpy_from_wc(dst_data + read_offset,
+ src_data + read_offset, bytes_to_copy);
+
+ src_data += buffer_size;
+ dst_data += buffer_size;
+ }
+
+ if (log_buf_snapshot_state)
+ guc_move_to_next_buf(guc);
+ else {
+ /* Used rate limited to avoid deluge of messages, logs might be
+ * getting consumed by User at a slow rate.
+ */
+ DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
+ guc->log.capture_miss_count++;
+ }
+}
+
+static void guc_log_cleanup(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+ /* First disable the flush interrupt */
+ gen9_disable_guc_interrupts(dev_priv);
+
+ if (guc->log.flush_wq)
+ destroy_workqueue(guc->log.flush_wq);
+
+ guc->log.flush_wq = NULL;
+
+ if (guc->log.relay_chan)
+ guc_log_remove_relay_file(guc);
+
+ guc->log.relay_chan = NULL;
+
+ if (guc->log.buf_addr)
+ i915_gem_object_unpin_map(guc->log.vma->obj);
+
+ guc->log.buf_addr = NULL;
+}
+
+static void capture_logs_work(struct work_struct *work)
+{
+ struct intel_guc *guc =
+ container_of(work, struct intel_guc, log.flush_work);
+
+ guc_log_capture_logs(guc);
+}
+
+static int guc_log_create_extras(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ void *vaddr;
+ int ret;
+
+ lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+ /* Nothing to do */
+ if (i915.guc_log_level < 0)
+ return 0;
+
+ if (!guc->log.buf_addr) {
+ /* Create a WC (Uncached for read) vmalloc mapping of log
+ * buffer pages, so that we can directly get the data
+ * (up-to-date) from memory.
+ */
+ vaddr = i915_gem_object_pin_map(guc->log.vma->obj, I915_MAP_WC);
+ if (IS_ERR(vaddr)) {
+ ret = PTR_ERR(vaddr);
+ DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
+ return ret;
+ }
+
+ guc->log.buf_addr = vaddr;
+ }
+
+ if (!guc->log.relay_chan) {
+ /* Create a relay channel, so that we have buffers for storing
+ * the GuC firmware logs, the channel will be linked with a file
+ * later on when debugfs is registered.
+ */
+ ret = guc_log_create_relay_channel(guc);
+ if (ret)
+ return ret;
+ }
+
+ if (!guc->log.flush_wq) {
+ INIT_WORK(&guc->log.flush_work, capture_logs_work);
+
+ /*
+ * GuC log buffer flush work item has to do register access to
+ * send the ack to GuC and this work item, if not synced before
+ * suspend, can potentially get executed after the GFX device is
+ * suspended.
+ * By marking the WQ as freezable, we don't have to bother about
+ * flushing of this work item from the suspend hooks, the pending
+ * work item if any will be either executed before the suspend
+ * or scheduled later on resume. This way the handling of work
+ * item can be kept same between system suspend & rpm suspend.
+ */
+ guc->log.flush_wq = alloc_ordered_workqueue("i915-guc_log",
+ WQ_HIGHPRI | WQ_FREEZABLE);
+ if (guc->log.flush_wq == NULL) {
+ DRM_ERROR("Couldn't allocate the wq for GuC logging\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+void intel_guc_log_create(struct intel_guc *guc)
+{
+ struct i915_vma *vma;
+ unsigned long offset;
+ uint32_t size, flags;
+
+ if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
+ i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
+
+ /* The first page is to save log buffer state. Allocate one
+ * extra page for others in case for overlap */
+ size = (1 + GUC_LOG_DPC_PAGES + 1 +
+ GUC_LOG_ISR_PAGES + 1 +
+ GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
+
+ vma = guc->log.vma;
+ if (!vma) {
+ /* We require SSE 4.1 for fast reads from the GuC log buffer and
+ * it should be present on the chipsets supporting GuC based
+ * submisssions.
+ */
+ if (WARN_ON(!i915_has_memcpy_from_wc())) {
+ /* logging will not be enabled */
+ i915.guc_log_level = -1;
+ return;
+ }
+
+ vma = intel_guc_allocate_vma(guc, size);
+ if (IS_ERR(vma)) {
+ /* logging will be off */
+ i915.guc_log_level = -1;
+ return;
+ }
+
+ guc->log.vma = vma;
+
+ if (guc_log_create_extras(guc)) {
+ guc_log_cleanup(guc);
+ i915_vma_unpin_and_release(&guc->log.vma);
+ i915.guc_log_level = -1;
+ return;
+ }
+ }
+
+ /* each allocated unit is a page */
+ flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
+ (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
+ (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
+ (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
+
+ offset = guc_ggtt_offset(vma) >> PAGE_SHIFT; /* in pages */
+ guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
+}
+
+static int guc_log_late_setup(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ int ret;
+
+ lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+ if (i915.guc_log_level < 0)
+ return -EINVAL;
+
+ /* If log_level was set as -1 at boot time, then setup needed to
+ * handle log buffer flush interrupts would not have been done yet,
+ * so do that now.
+ */
+ ret = guc_log_create_extras(guc);
+ if (ret)
+ goto err;
+
+ ret = guc_log_create_relay_file(guc);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ guc_log_cleanup(guc);
+ /* logging will remain off */
+ i915.guc_log_level = -1;
+ return ret;
+}
+
+static void guc_log_capture_logs(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ guc_read_update_log_buffer(guc);
+
+ /* Generally device is expected to be active only at this
+ * time, so get/put should be really quick.
+ */
+ intel_runtime_pm_get(dev_priv);
+ guc_log_flush_complete(guc);
+ intel_runtime_pm_put(dev_priv);
+}
+
+static void guc_flush_logs(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ if (!i915.enable_guc_submission || (i915.guc_log_level < 0))
+ return;
+
+ /* First disable the interrupts, will be renabled afterwards */
+ gen9_disable_guc_interrupts(dev_priv);
+
+ /* Before initiating the forceful flush, wait for any pending/ongoing
+ * flush to complete otherwise forceful flush may not actually happen.
+ */
+ flush_work(&guc->log.flush_work);
+
+ /* Ask GuC to update the log buffer state */
+ guc_log_flush(guc);
+
+ /* GuC would have updated log buffer by now, so capture it */
+ guc_log_capture_logs(guc);
+}
+
+int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+
+ union guc_log_control log_param;
+ int ret;
+
+ log_param.value = control_val;
+
+ if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
+ log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
+ return -EINVAL;
+
+ /* This combination doesn't make sense & won't have any effect */
+ if (!log_param.logging_enabled && (i915.guc_log_level < 0))
+ return 0;
+
+ ret = guc_log_control(guc, log_param.value);
+ if (ret < 0) {
+ DRM_DEBUG_DRIVER("guc_logging_control action failed %d\n", ret);
+ return ret;
+ }
+
+ i915.guc_log_level = log_param.verbosity;
+
+ /* If log_level was set as -1 at boot time, then the relay channel file
+ * wouldn't have been created by now and interrupts also would not have
+ * been enabled.
+ */
+ if (!dev_priv->guc.log.relay_chan) {
+ ret = guc_log_late_setup(guc);
+ if (!ret)
+ gen9_enable_guc_interrupts(dev_priv);
+ } else if (!log_param.logging_enabled) {
+ /* Once logging is disabled, GuC won't generate logs & send an
+ * interrupt. But there could be some data in the log buffer
+ * which is yet to be captured. So request GuC to update the log
+ * buffer state and then collect the left over logs.
+ */
+ guc_flush_logs(guc);
+
+ /* As logging is disabled, update log level to reflect that */
+ i915.guc_log_level = -1;
+ } else {
+ /* In case interrupts were disabled, enable them now */
+ gen9_enable_guc_interrupts(dev_priv);
+ }
+
+ return ret;
+}
+
+void i915_guc_log_register(struct drm_i915_private *dev_priv)
+{
+ if (!i915.enable_guc_submission)
+ return;
+
+ mutex_lock(&dev_priv->drm.struct_mutex);
+ guc_log_late_setup(&dev_priv->guc);
+ mutex_unlock(&dev_priv->drm.struct_mutex);
+}
+
+void i915_guc_log_unregister(struct drm_i915_private *dev_priv)
+{
+ if (!i915.enable_guc_submission)
+ return;
+
+ mutex_lock(&dev_priv->drm.struct_mutex);
+ guc_log_cleanup(&dev_priv->guc);
+ mutex_unlock(&dev_priv->drm.struct_mutex);
+}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 0bcfead14571..af16b0fa6b69 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -455,24 +455,23 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->base.adjusted_mode;
union hdmi_infoframe frame;
int ret;
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
- &crtc_state->base.adjusted_mode);
+ adjusted_mode);
if (ret < 0) {
DRM_ERROR("couldn't fill AVI infoframe\n");
return;
}
- if (intel_hdmi->rgb_quant_range_selectable) {
- if (crtc_state->limited_color_range)
- frame.avi.quantization_range =
- HDMI_QUANTIZATION_RANGE_LIMITED;
- else
- frame.avi.quantization_range =
- HDMI_QUANTIZATION_RANGE_FULL;
- }
+ drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
+ crtc_state->limited_color_range ?
+ HDMI_QUANTIZATION_RANGE_LIMITED :
+ HDMI_QUANTIZATION_RANGE_FULL,
+ intel_hdmi->rgb_quant_range_selectable);
intel_write_infoframe(encoder, crtc_state, &frame);
}
@@ -1330,7 +1329,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
/* See CEA-861-E - 5.1 Default Encoding Parameters */
pipe_config->limited_color_range =
pipe_config->has_hdmi_sink &&
- drm_match_cea_mode(adjusted_mode) > 1;
+ drm_default_rgb_quant_range(adjusted_mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED;
} else {
pipe_config->limited_color_range =
intel_hdmi->limited_color_range;
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 3d546c019de0..b62e3f8ad415 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -180,7 +180,7 @@ static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv)
/* Enable polling and queue hotplug re-enabling. */
if (hpd_disabled) {
- drm_kms_helper_poll_enable_locked(dev);
+ drm_kms_helper_poll_enable(dev);
mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work,
msecs_to_jiffies(HPD_STORM_REENABLE_DELAY));
}
@@ -511,7 +511,7 @@ static void i915_hpd_poll_init_work(struct work_struct *work)
}
if (enabled)
- drm_kms_helper_poll_enable_locked(dev);
+ drm_kms_helper_poll_enable(dev);
mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c
new file mode 100644
index 000000000000..c144609425f6
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_huc.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2016-2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_uc.h"
+
+/**
+ * DOC: HuC Firmware
+ *
+ * Motivation:
+ * GEN9 introduces a new dedicated firmware for usage in media HEVC (High
+ * Efficiency Video Coding) operations. Userspace can use the firmware
+ * capabilities by adding HuC specific commands to batch buffers.
+ *
+ * Implementation:
+ * The same firmware loader is used as the GuC. However, the actual
+ * loading to HW is deferred until GEM initialization is done.
+ *
+ * Note that HuC firmware loading must be done before GuC loading.
+ */
+
+#define BXT_HUC_FW_MAJOR 01
+#define BXT_HUC_FW_MINOR 07
+#define BXT_BLD_NUM 1398
+
+#define SKL_HUC_FW_MAJOR 01
+#define SKL_HUC_FW_MINOR 07
+#define SKL_BLD_NUM 1398
+
+#define KBL_HUC_FW_MAJOR 02
+#define KBL_HUC_FW_MINOR 00
+#define KBL_BLD_NUM 1810
+
+#define HUC_FW_PATH(platform, major, minor, bld_num) \
+ "i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \
+ __stringify(minor) "_" __stringify(bld_num) ".bin"
+
+#define I915_SKL_HUC_UCODE HUC_FW_PATH(skl, SKL_HUC_FW_MAJOR, \
+ SKL_HUC_FW_MINOR, SKL_BLD_NUM)
+MODULE_FIRMWARE(I915_SKL_HUC_UCODE);
+
+#define I915_BXT_HUC_UCODE HUC_FW_PATH(bxt, BXT_HUC_FW_MAJOR, \
+ BXT_HUC_FW_MINOR, BXT_BLD_NUM)
+MODULE_FIRMWARE(I915_BXT_HUC_UCODE);
+
+#define I915_KBL_HUC_UCODE HUC_FW_PATH(kbl, KBL_HUC_FW_MAJOR, \
+ KBL_HUC_FW_MINOR, KBL_BLD_NUM)
+MODULE_FIRMWARE(I915_KBL_HUC_UCODE);
+
+/**
+ * huc_ucode_xfer() - DMA's the firmware
+ * @dev_priv: the drm_i915_private device
+ *
+ * Transfer the firmware image to RAM for execution by the microcontroller.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int huc_ucode_xfer(struct drm_i915_private *dev_priv)
+{
+ struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
+ struct i915_vma *vma;
+ unsigned long offset = 0;
+ u32 size;
+ int ret;
+
+ ret = i915_gem_object_set_to_gtt_domain(huc_fw->obj, false);
+ if (ret) {
+ DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
+ return ret;
+ }
+
+ vma = i915_gem_object_ggtt_pin(huc_fw->obj, NULL, 0, 0,
+ PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+ if (IS_ERR(vma)) {
+ DRM_DEBUG_DRIVER("pin failed %d\n", (int)PTR_ERR(vma));
+ return PTR_ERR(vma);
+ }
+
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+ /* init WOPCM */
+ I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv));
+ I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE |
+ HUC_LOADING_AGENT_GUC);
+
+ /* Set the source address for the uCode */
+ offset = guc_ggtt_offset(vma) + huc_fw->header_offset;
+ I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
+ I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
+
+ /* Hardware doesn't look at destination address for HuC. Set it to 0,
+ * but still program the correct address space.
+ */
+ I915_WRITE(DMA_ADDR_1_LOW, 0);
+ I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
+
+ size = huc_fw->header_size + huc_fw->ucode_size;
+ I915_WRITE(DMA_COPY_SIZE, size);
+
+ /* Start the DMA */
+ I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(HUC_UKERNEL | START_DMA));
+
+ /* Wait for DMA to finish */
+ ret = wait_for((I915_READ(DMA_CTRL) & START_DMA) == 0, 100);
+
+ DRM_DEBUG_DRIVER("HuC DMA transfer wait over with ret %d\n", ret);
+
+ /* Disable the bits once DMA is over */
+ I915_WRITE(DMA_CTRL, _MASKED_BIT_DISABLE(HUC_UKERNEL));
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+ /*
+ * We keep the object pages for reuse during resume. But we can unpin it
+ * now that DMA has completed, so it doesn't continue to take up space.
+ */
+ i915_vma_unpin(vma);
+
+ return ret;
+}
+
+/**
+ * intel_huc_init() - initiate HuC firmware loading request
+ * @dev_priv: the drm_i915_private device
+ *
+ * Called early during driver load, but after GEM is initialised. The loading
+ * will continue only when driver explicitly specify firmware name and version.
+ * All other cases are considered as INTEL_UC_FIRMWARE_NONE either because HW
+ * is not capable or driver yet support it. And there will be no error message
+ * for INTEL_UC_FIRMWARE_NONE cases.
+ *
+ * The DMA-copying to HW is done later when intel_huc_load() is called.
+ */
+void intel_huc_init(struct drm_i915_private *dev_priv)
+{
+ struct intel_huc *huc = &dev_priv->huc;
+ struct intel_uc_fw *huc_fw = &huc->fw;
+ const char *fw_path = NULL;
+
+ huc_fw->path = NULL;
+ huc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
+ huc_fw->load_status = INTEL_UC_FIRMWARE_NONE;
+ huc_fw->fw = INTEL_UC_FW_TYPE_HUC;
+
+ if (!HAS_HUC_UCODE(dev_priv))
+ return;
+
+ if (IS_SKYLAKE(dev_priv)) {
+ fw_path = I915_SKL_HUC_UCODE;
+ huc_fw->major_ver_wanted = SKL_HUC_FW_MAJOR;
+ huc_fw->minor_ver_wanted = SKL_HUC_FW_MINOR;
+ } else if (IS_BROXTON(dev_priv)) {
+ fw_path = I915_BXT_HUC_UCODE;
+ huc_fw->major_ver_wanted = BXT_HUC_FW_MAJOR;
+ huc_fw->minor_ver_wanted = BXT_HUC_FW_MINOR;
+ } else if (IS_KABYLAKE(dev_priv)) {
+ fw_path = I915_KBL_HUC_UCODE;
+ huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR;
+ huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR;
+ }
+
+ huc_fw->path = fw_path;
+ huc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
+
+ DRM_DEBUG_DRIVER("HuC firmware pending, path %s\n", fw_path);
+
+ WARN(huc_fw->path == NULL, "HuC present but no fw path\n");
+
+ intel_uc_fw_fetch(dev_priv, huc_fw);
+}
+
+/**
+ * intel_huc_load() - load HuC uCode to device
+ * @dev_priv: the drm_i915_private device
+ *
+ * Called from guc_setup() during driver loading and also after a GPU reset.
+ * Be note that HuC loading must be done before GuC loading.
+ *
+ * The firmware image should have already been fetched into memory by the
+ * earlier call to intel_huc_init(), so here we need only check that
+ * is succeeded, and then transfer the image to the h/w.
+ *
+ * Return: non-zero code on error
+ */
+int intel_huc_load(struct drm_i915_private *dev_priv)
+{
+ struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
+ int err;
+
+ if (huc_fw->fetch_status == INTEL_UC_FIRMWARE_NONE)
+ return 0;
+
+ DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
+ huc_fw->path,
+ intel_uc_fw_status_repr(huc_fw->fetch_status),
+ intel_uc_fw_status_repr(huc_fw->load_status));
+
+ if (huc_fw->fetch_status == INTEL_UC_FIRMWARE_SUCCESS &&
+ huc_fw->load_status == INTEL_UC_FIRMWARE_FAIL)
+ return -ENOEXEC;
+
+ huc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
+
+ switch (huc_fw->fetch_status) {
+ case INTEL_UC_FIRMWARE_FAIL:
+ /* something went wrong :( */
+ err = -EIO;
+ goto fail;
+
+ case INTEL_UC_FIRMWARE_NONE:
+ case INTEL_UC_FIRMWARE_PENDING:
+ default:
+ /* "can't happen" */
+ WARN_ONCE(1, "HuC fw %s invalid fetch_status %s [%d]\n",
+ huc_fw->path,
+ intel_uc_fw_status_repr(huc_fw->fetch_status),
+ huc_fw->fetch_status);
+ err = -ENXIO;
+ goto fail;
+
+ case INTEL_UC_FIRMWARE_SUCCESS:
+ break;
+ }
+
+ err = huc_ucode_xfer(dev_priv);
+ if (err)
+ goto fail;
+
+ huc_fw->load_status = INTEL_UC_FIRMWARE_SUCCESS;
+
+ DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n",
+ huc_fw->path,
+ intel_uc_fw_status_repr(huc_fw->fetch_status),
+ intel_uc_fw_status_repr(huc_fw->load_status));
+
+ return 0;
+
+fail:
+ if (huc_fw->load_status == INTEL_UC_FIRMWARE_PENDING)
+ huc_fw->load_status = INTEL_UC_FIRMWARE_FAIL;
+
+ DRM_ERROR("Failed to complete HuC uCode load with ret %d\n", err);
+
+ return err;
+}
+
+/**
+ * intel_huc_fini() - clean up resources allocated for HuC
+ * @dev_priv: the drm_i915_private device
+ *
+ * Cleans up by releasing the huc firmware GEM obj.
+ */
+void intel_huc_fini(struct drm_i915_private *dev_priv)
+{
+ struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
+
+ mutex_lock(&dev_priv->drm.struct_mutex);
+ if (huc_fw->obj)
+ i915_gem_object_put(huc_fw->obj);
+ huc_fw->obj = NULL;
+ mutex_unlock(&dev_priv->drm.struct_mutex);
+
+ huc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
+}
+
+/**
+ * intel_guc_auth_huc() - authenticate ucode
+ * @dev_priv: the drm_i915_device
+ *
+ * Triggers a HuC fw authentication request to the GuC via intel_guc_action_
+ * authenticate_huc interface.
+ */
+void intel_guc_auth_huc(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+ struct intel_huc *huc = &dev_priv->huc;
+ struct i915_vma *vma;
+ int ret;
+ u32 data[2];
+
+ if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
+ return;
+
+ vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
+ PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+ if (IS_ERR(vma)) {
+ DRM_ERROR("failed to pin huc fw object %d\n",
+ (int)PTR_ERR(vma));
+ return;
+ }
+
+ /* Specify auth action and where public signature is. */
+ data[0] = INTEL_GUC_ACTION_AUTHENTICATE_HUC;
+ data[1] = guc_ggtt_offset(vma) + huc->fw.rsa_offset;
+
+ ret = intel_guc_send(guc, data, ARRAY_SIZE(data));
+ if (ret) {
+ DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret);
+ goto out;
+ }
+
+ /* Check authentication status, it should be done by now */
+ ret = intel_wait_for_register(dev_priv,
+ HUC_STATUS2,
+ HUC_FW_VERIFIED,
+ HUC_FW_VERIFIED,
+ 50);
+
+ if (ret) {
+ DRM_ERROR("HuC: Authentication failed %d\n", ret);
+ goto out;
+ }
+
+out:
+ i915_vma_unpin(vma);
+}
+
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 6db246ad2f13..432ee495dec2 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -811,12 +811,6 @@ static int execlists_context_pin(struct intel_engine_cs *engine,
ce->state->obj->mm.dirty = true;
- /* Invalidate GuC TLB. */
- if (i915.enable_guc_submission) {
- struct drm_i915_private *dev_priv = ctx->i915;
- I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
- }
-
i915_gem_context_get(ctx);
return 0;
@@ -970,18 +964,8 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine,
uint32_t *batch,
uint32_t index)
{
- struct drm_i915_private *dev_priv = engine->i915;
uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES);
- /*
- * WaDisableLSQCROPERFforOCL:kbl
- * This WA is implemented in skl_init_clock_gating() but since
- * this batch updates GEN8_L3SQCREG4 with default value we need to
- * set this bit here to retain the WA during flush.
- */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
- l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
-
wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
@@ -1241,7 +1225,7 @@ static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *engine, u32 size)
if (IS_ERR(obj))
return PTR_ERR(obj);
- vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
if (IS_ERR(vma)) {
err = PTR_ERR(vma);
goto err;
@@ -1927,7 +1911,7 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
engine->emit_breadcrumb = gen8_emit_breadcrumb_render;
engine->emit_breadcrumb_sz = gen8_emit_breadcrumb_render_sz;
- ret = intel_engine_create_scratch(engine, 4096);
+ ret = intel_engine_create_scratch(engine, PAGE_SIZE);
if (ret)
return ret;
@@ -2103,19 +2087,12 @@ static void execlists_init_reg_state(u32 *reg_state,
ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(engine, 0),
0);
- if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+ if (ppgtt && USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
/* 64b PPGTT (48bit canonical)
* PDP0_DESCRIPTOR contains the base address to PML4 and
* other PDP Descriptors are ignored.
*/
ASSIGN_CTX_PML4(ppgtt, reg_state);
- } else {
- /* 32b PPGTT
- * PDP*_DESCRIPTOR contains the base address of space supported.
- * With dynamic page allocation, PDPs may not be allocated at
- * this point. Point the unallocated PDPs to the scratch page
- */
- execlists_update_context_pdps(ppgtt, reg_state);
}
if (engine->id == RCS) {
@@ -2209,7 +2186,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
WARN_ON(ce->state);
- context_size = round_up(intel_lr_context_size(engine), 4096);
+ context_size = round_up(intel_lr_context_size(engine),
+ I915_GTT_PAGE_SIZE);
/* One extra page as the sharing data between driver and GuC */
context_size += PAGE_SIZE * LRC_PPHWSP_PN;
@@ -2220,7 +2198,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
return PTR_ERR(ctx_obj);
}
- vma = i915_vma_create(ctx_obj, &ctx->i915->ggtt.base, NULL);
+ vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.base, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto error_deref_obj;
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 01ba36ea125e..0c852c024227 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -26,7 +26,7 @@
#include "intel_ringbuffer.h"
-#define GEN8_LR_CONTEXT_ALIGN 4096
+#define GEN8_LR_CONTEXT_ALIGN I915_GTT_MIN_ALIGNMENT
/* Execlists regs */
#define RING_ELSP(engine) _MMIO((engine)->mmio_base + 0x230)
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 4473a611c664..0608fad7f593 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -811,8 +811,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
if (ret != 0)
return ret;
- vma = i915_gem_object_pin_to_display_plane(new_bo, 0,
- &i915_ggtt_view_normal);
+ vma = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
if (IS_ERR(vma))
return PTR_ERR(vma);
diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c
index ef0c0e195164..c0b1f99da37b 100644
--- a/drivers/gpu/drm/i915/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/intel_pipe_crc.c
@@ -560,14 +560,14 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
state = drm_atomic_state_alloc(dev);
if (!state) {
ret = -ENOMEM;
- goto out;
+ goto unlock;
}
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(&crtc->base);
pipe_config = intel_atomic_get_crtc_state(state, crtc);
if (IS_ERR(pipe_config)) {
ret = PTR_ERR(pipe_config);
- goto out;
+ goto put_state;
}
pipe_config->pch_pfit.force_thru = enable;
@@ -576,10 +576,12 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
pipe_config->base.connectors_changed = true;
ret = drm_atomic_commit(state);
-out:
+
+put_state:
+ drm_atomic_state_put(state);
+unlock:
WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret);
drm_modeset_unlock_all(dev);
- drm_atomic_state_put(state);
}
static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
@@ -613,6 +615,22 @@ static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
return 0;
}
+static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv,
+ enum pipe pipe,
+ enum intel_pipe_crc_source *source, u32 *val)
+{
+ if (IS_GEN2(dev_priv))
+ return i8xx_pipe_crc_ctl_reg(source, val);
+ else if (INTEL_GEN(dev_priv) < 5)
+ return i9xx_pipe_crc_ctl_reg(dev_priv, pipe, source, val);
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ return vlv_pipe_crc_ctl_reg(dev_priv, pipe, source, val);
+ else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv))
+ return ilk_pipe_crc_ctl_reg(source, val);
+ else
+ return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val);
+}
+
static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
enum pipe pipe,
enum intel_pipe_crc_source source)
@@ -636,17 +654,7 @@ static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
return -EIO;
}
- if (IS_GEN2(dev_priv))
- ret = i8xx_pipe_crc_ctl_reg(&source, &val);
- else if (INTEL_GEN(dev_priv) < 5)
- ret = i9xx_pipe_crc_ctl_reg(dev_priv, pipe, &source, &val);
- else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- ret = vlv_pipe_crc_ctl_reg(dev_priv, pipe, &source, &val);
- else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv))
- ret = ilk_pipe_crc_ctl_reg(&source, &val);
- else
- ret = ivb_pipe_crc_ctl_reg(dev_priv, pipe, &source, &val);
-
+ ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val);
if (ret != 0)
goto out;
@@ -687,7 +695,7 @@ static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
POSTING_READ(PIPE_CRC_CTL(pipe));
/* real source -> none transition */
- if (source == INTEL_PIPE_CRC_SOURCE_NONE) {
+ if (!source) {
struct intel_pipe_crc_entry *entries;
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv,
pipe);
@@ -809,6 +817,11 @@ display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s)
{
int i;
+ if (!buf) {
+ *s = INTEL_PIPE_CRC_SOURCE_NONE;
+ return 0;
+ }
+
for (i = 0; i < ARRAY_SIZE(pipe_crc_sources); i++)
if (!strcmp(buf, pipe_crc_sources[i])) {
*s = i;
@@ -937,3 +950,62 @@ void intel_pipe_crc_cleanup(struct drm_minor *minor)
drm_debugfs_remove_files(info_list, 1, minor);
}
}
+
+int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
+ size_t *values_cnt)
+{
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+ struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum intel_display_power_domain power_domain;
+ enum intel_pipe_crc_source source;
+ u32 val = 0; /* shut up gcc */
+ int ret = 0;
+
+ if (display_crc_ctl_parse_source(source_name, &source) < 0) {
+ DRM_DEBUG_DRIVER("unknown source %s\n", source_name);
+ return -EINVAL;
+ }
+
+ power_domain = POWER_DOMAIN_PIPE(crtc->index);
+ if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
+ DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
+ return -EIO;
+ }
+
+ ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val);
+ if (ret != 0)
+ goto out;
+
+ if (source) {
+ /*
+ * When IPS gets enabled, the pipe CRC changes. Since IPS gets
+ * enabled and disabled dynamically based on package C states,
+ * user space can't make reliable use of the CRCs, so let's just
+ * completely disable it.
+ */
+ hsw_disable_ips(intel_crtc);
+ }
+
+ I915_WRITE(PIPE_CRC_CTL(crtc->index), val);
+ POSTING_READ(PIPE_CRC_CTL(crtc->index));
+
+ if (!source) {
+ if (IS_G4X(dev_priv))
+ g4x_undo_pipe_scramble_reset(dev_priv, crtc->index);
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ vlv_undo_pipe_scramble_reset(dev_priv, crtc->index);
+ else if (IS_HASWELL(dev_priv) && crtc->index == PIPE_A)
+ hsw_trans_edp_pipe_A_crc_wa(dev_priv, false);
+
+ hsw_enable_ips(intel_crtc);
+ }
+
+ pipe_crc->skipped = 0;
+ *values_cnt = 5;
+
+out:
+ intel_display_power_put(dev_priv, power_domain);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 6aca8ff14989..c3780d0d2baf 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -122,13 +122,26 @@ static void vlv_psr_setup_vsc(struct intel_dp *intel_dp)
static void skl_psr_setup_su_vsc(struct intel_dp *intel_dp)
{
struct edp_vsc_psr psr_vsc;
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
/* Prepare VSC Header for SU as per EDP 1.4 spec, Table 6.11 */
memset(&psr_vsc, 0, sizeof(psr_vsc));
psr_vsc.sdp_header.HB0 = 0;
psr_vsc.sdp_header.HB1 = 0x7;
- psr_vsc.sdp_header.HB2 = 0x3;
- psr_vsc.sdp_header.HB3 = 0xb;
+ if (dev_priv->psr.colorimetry_support &&
+ dev_priv->psr.y_cord_support) {
+ psr_vsc.sdp_header.HB2 = 0x5;
+ psr_vsc.sdp_header.HB3 = 0x13;
+ } else if (dev_priv->psr.y_cord_support) {
+ psr_vsc.sdp_header.HB2 = 0x4;
+ psr_vsc.sdp_header.HB3 = 0xe;
+ } else {
+ psr_vsc.sdp_header.HB2 = 0x3;
+ psr_vsc.sdp_header.HB3 = 0xc;
+ }
+
intel_psr_write_vsc(intel_dp, &psr_vsc);
}
@@ -196,7 +209,11 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
drm_dp_dpcd_writeb(&intel_dp->aux,
DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF,
DP_AUX_FRAME_SYNC_ENABLE);
-
+ /* Enable ALPM at sink for psr2 */
+ if (dev_priv->psr.psr2_support && dev_priv->psr.alpm)
+ drm_dp_dpcd_writeb(&intel_dp->aux,
+ DP_RECEIVER_ALPM_CONFIG,
+ DP_ALPM_ENABLE);
if (dev_priv->psr.link_standby)
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
@@ -248,7 +265,7 @@ static void vlv_psr_activate(struct intel_dp *intel_dp)
VLV_EDP_PSR_ACTIVE_ENTRY);
}
-static void hsw_psr_enable_source(struct intel_dp *intel_dp)
+static void intel_enable_source_psr1(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
@@ -299,14 +316,31 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
val |= EDP_PSR_TP1_TP2_SEL;
I915_WRITE(EDP_PSR_CTL, val);
+}
- if (!dev_priv->psr.psr2_support)
- return;
+static void intel_enable_source_psr2(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ /*
+ * Let's respect VBT in case VBT asks a higher idle_frame value.
+ * Let's use 6 as the minimum to cover all known cases including
+ * the off-by-one issue that HW has in some cases. Also there are
+ * cases where sink should be able to train
+ * with the 5 or 6 idle patterns.
+ */
+ uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames);
+ uint32_t val;
+
+ val = idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
/* FIXME: selective update is probably totally broken because it doesn't
* mesh at all with our frontbuffer tracking. And the hw alone isn't
* good enough. */
- val = EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE;
+ val |= EDP_PSR2_ENABLE |
+ EDP_SU_TRACK_ENABLE |
+ EDP_FRAMES_BEFORE_SU_ENTRY;
if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5)
val |= EDP_PSR2_TP2_TIME_2500;
@@ -320,6 +354,19 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
I915_WRITE(EDP_PSR2_CTL, val);
}
+static void hsw_psr_enable_source(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+
+ /* psr1 and psr2 are mutually exclusive.*/
+ if (dev_priv->psr.psr2_support)
+ intel_enable_source_psr2(intel_dp);
+ else
+ intel_enable_source_psr1(intel_dp);
+}
+
static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@@ -387,6 +434,22 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
return false;
}
+ /* PSR2 is restricted to work with panel resolutions upto 3200x2000 */
+ if (intel_crtc->config->pipe_src_w > 3200 ||
+ intel_crtc->config->pipe_src_h > 2000) {
+ dev_priv->psr.psr2_support = false;
+ return false;
+ }
+
+ /*
+ * FIXME:enable psr2 only for y-cordinate psr2 panels
+ * After gtc implementation , remove this restriction.
+ */
+ if (!dev_priv->psr.y_cord_support && dev_priv->psr.psr2_support) {
+ DRM_DEBUG_KMS("PSR2 disabled, panel does not support Y coordinate\n");
+ return false;
+ }
+
dev_priv->psr.source_ok = true;
return true;
}
@@ -397,7 +460,10 @@ static void intel_psr_activate(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
- WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
+ if (dev_priv->psr.psr2_support)
+ WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
+ else
+ WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
WARN_ON(dev_priv->psr.active);
lockdep_assert_held(&dev_priv->psr.lock);
@@ -426,6 +492,8 @@ void intel_psr_enable(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+ u32 chicken;
if (!HAS_PSR(dev_priv)) {
DRM_DEBUG_KMS("PSR not supported on this platform\n");
@@ -449,26 +517,34 @@ void intel_psr_enable(struct intel_dp *intel_dp)
dev_priv->psr.busy_frontbuffer_bits = 0;
if (HAS_DDI(dev_priv)) {
- hsw_psr_setup_vsc(intel_dp);
-
if (dev_priv->psr.psr2_support) {
- /* PSR2 is restricted to work with panel resolutions upto 3200x2000 */
- if (crtc->config->pipe_src_w > 3200 ||
- crtc->config->pipe_src_h > 2000)
- dev_priv->psr.psr2_support = false;
- else
- skl_psr_setup_su_vsc(intel_dp);
+ skl_psr_setup_su_vsc(intel_dp);
+ chicken = PSR2_VSC_ENABLE_PROG_HEADER;
+ if (dev_priv->psr.y_cord_support)
+ chicken |= PSR2_ADD_VERTICAL_LINE_COUNT;
+ I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken);
+ I915_WRITE(EDP_PSR_DEBUG_CTL,
+ EDP_PSR_DEBUG_MASK_MEMUP |
+ EDP_PSR_DEBUG_MASK_HPD |
+ EDP_PSR_DEBUG_MASK_LPSP |
+ EDP_PSR_DEBUG_MASK_MAX_SLEEP |
+ EDP_PSR_DEBUG_MASK_DISP_REG_WRITE);
+ } else {
+ /* set up vsc header for psr1 */
+ hsw_psr_setup_vsc(intel_dp);
+ /*
+ * Per Spec: Avoid continuous PSR exit by masking MEMUP
+ * and HPD. also mask LPSP to avoid dependency on other
+ * drivers that might block runtime_pm besides
+ * preventing other hw tracking issues now we can rely
+ * on frontbuffer tracking.
+ */
+ I915_WRITE(EDP_PSR_DEBUG_CTL,
+ EDP_PSR_DEBUG_MASK_MEMUP |
+ EDP_PSR_DEBUG_MASK_HPD |
+ EDP_PSR_DEBUG_MASK_LPSP);
}
- /*
- * Per Spec: Avoid continuous PSR exit by masking MEMUP and HPD.
- * Also mask LPSP to avoid dependency on other drivers that
- * might block runtime_pm besides preventing other hw tracking
- * issues now we can rely on frontbuffer tracking.
- */
- I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
- EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
-
/* Enable PSR on the panel */
hsw_psr_enable_sink(intel_dp);
@@ -544,20 +620,42 @@ static void hsw_psr_disable(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = to_i915(dev);
if (dev_priv->psr.active) {
- I915_WRITE(EDP_PSR_CTL,
- I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
+ i915_reg_t psr_ctl;
+ u32 psr_status_mask;
+
+ if (dev_priv->psr.aux_frame_sync)
+ drm_dp_dpcd_writeb(&intel_dp->aux,
+ DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF,
+ 0);
+
+ if (dev_priv->psr.psr2_support) {
+ psr_ctl = EDP_PSR2_CTL;
+ psr_status_mask = EDP_PSR2_STATUS_STATE_MASK;
+
+ I915_WRITE(psr_ctl,
+ I915_READ(psr_ctl) &
+ ~(EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE));
+
+ } else {
+ psr_ctl = EDP_PSR_STATUS_CTL;
+ psr_status_mask = EDP_PSR_STATUS_STATE_MASK;
+
+ I915_WRITE(psr_ctl,
+ I915_READ(psr_ctl) & ~EDP_PSR_ENABLE);
+ }
/* Wait till PSR is idle */
if (intel_wait_for_register(dev_priv,
- EDP_PSR_STATUS_CTL,
- EDP_PSR_STATUS_STATE_MASK,
- 0,
+ psr_ctl, psr_status_mask, 0,
2000))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
dev_priv->psr.active = false;
} else {
- WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
+ if (dev_priv->psr.psr2_support)
+ WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
+ else
+ WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
}
}
@@ -608,13 +706,24 @@ static void intel_psr_work(struct work_struct *work)
* and be ready for re-enable.
*/
if (HAS_DDI(dev_priv)) {
- if (intel_wait_for_register(dev_priv,
- EDP_PSR_STATUS_CTL,
- EDP_PSR_STATUS_STATE_MASK,
- 0,
- 50)) {
- DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
- return;
+ if (dev_priv->psr.psr2_support) {
+ if (intel_wait_for_register(dev_priv,
+ EDP_PSR2_STATUS_CTL,
+ EDP_PSR2_STATUS_STATE_MASK,
+ 0,
+ 50)) {
+ DRM_ERROR("Timed out waiting for PSR2 Idle for re-enable\n");
+ return;
+ }
+ } else {
+ if (intel_wait_for_register(dev_priv,
+ EDP_PSR_STATUS_CTL,
+ EDP_PSR_STATUS_STATE_MASK,
+ 0,
+ 50)) {
+ DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+ return;
+ }
}
} else {
if (intel_wait_for_register(dev_priv,
@@ -656,11 +765,19 @@ static void intel_psr_exit(struct drm_i915_private *dev_priv)
return;
if (HAS_DDI(dev_priv)) {
- val = I915_READ(EDP_PSR_CTL);
-
- WARN_ON(!(val & EDP_PSR_ENABLE));
-
- I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
+ if (dev_priv->psr.aux_frame_sync)
+ drm_dp_dpcd_writeb(&intel_dp->aux,
+ DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF,
+ 0);
+ if (dev_priv->psr.psr2_support) {
+ val = I915_READ(EDP_PSR2_CTL);
+ WARN_ON(!(val & EDP_PSR2_ENABLE));
+ I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE);
+ } else {
+ val = I915_READ(EDP_PSR_CTL);
+ WARN_ON(!(val & EDP_PSR_ENABLE));
+ I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
+ }
} else {
val = I915_READ(VLV_PSRCTL(pipe));
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 0971ac396b60..69035e4f9b3b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1095,14 +1095,6 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine)
WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FENCE_DEST_SLM_DISABLE);
- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
- * involving this register should also be added to WA batch as required.
- */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
- /* WaDisableLSQCROPERFforOCL:kbl */
- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
- GEN8_LQSC_RO_PERF_DIS);
-
/* WaToEnableHwFixForPushConstHWBug:kbl */
if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER))
WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
@@ -1736,7 +1728,7 @@ static int init_status_page(struct intel_engine_cs *engine)
void *vaddr;
int ret;
- obj = i915_gem_object_create_internal(engine->i915, 4096);
+ obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
if (IS_ERR(obj)) {
DRM_ERROR("Failed to allocate status page\n");
return PTR_ERR(obj);
@@ -1746,7 +1738,7 @@ static int init_status_page(struct intel_engine_cs *engine)
if (ret)
goto err;
- vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto err;
@@ -1777,7 +1769,7 @@ static int init_status_page(struct intel_engine_cs *engine)
engine->status_page.vma = vma;
engine->status_page.ggtt_offset = i915_ggtt_offset(vma);
- engine->status_page.page_addr = memset(vaddr, 0, 4096);
+ engine->status_page.page_addr = memset(vaddr, 0, PAGE_SIZE);
DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
engine->name, i915_ggtt_offset(vma));
@@ -1880,7 +1872,7 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
/* mark ring buffers as read-only from GPU side by default */
obj->gt_ro = 1;
- vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
if (IS_ERR(vma))
goto err;
@@ -2049,7 +2041,7 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
}
/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
- ret = intel_ring_pin(ring, 4096);
+ ret = intel_ring_pin(ring, I915_GTT_PAGE_SIZE);
if (ret) {
intel_ring_free(ring);
goto error;
@@ -2466,11 +2458,11 @@ static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
if (INTEL_GEN(dev_priv) >= 8 && !dev_priv->semaphore) {
struct i915_vma *vma;
- obj = i915_gem_object_create(dev_priv, 4096);
+ obj = i915_gem_object_create(dev_priv, PAGE_SIZE);
if (IS_ERR(obj))
goto err;
- vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+ vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
if (IS_ERR(vma))
goto err_obj;
@@ -2683,7 +2675,7 @@ int intel_init_render_ring_buffer(struct intel_engine_cs *engine)
return ret;
if (INTEL_GEN(dev_priv) >= 6) {
- ret = intel_engine_create_scratch(engine, 4096);
+ ret = intel_engine_create_scratch(engine, PAGE_SIZE);
if (ret)
return ret;
} else if (HAS_BROKEN_CS_TLB(dev_priv)) {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 7031bc733d97..9ef54688872a 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -273,7 +273,7 @@ skl_update_plane(struct drm_plane *drm_plane,
I915_WRITE(PLANE_CTL(pipe, plane_id), plane_ctl);
I915_WRITE(PLANE_SURF(pipe, plane_id),
- intel_fb_gtt_offset(fb, rotation) + surf_addr);
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
POSTING_READ(PLANE_SURF(pipe, plane_id));
}
@@ -458,7 +458,7 @@ vlv_update_plane(struct drm_plane *dplane,
I915_WRITE(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
I915_WRITE(SPCNTR(pipe, plane_id), sprctl);
I915_WRITE(SPSURF(pipe, plane_id),
- intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+ intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
POSTING_READ(SPSURF(pipe, plane_id));
}
@@ -594,7 +594,7 @@ ivb_update_plane(struct drm_plane *plane,
I915_WRITE(SPRSCALE(pipe), sprscale);
I915_WRITE(SPRCTL(pipe), sprctl);
I915_WRITE(SPRSURF(pipe),
- intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+ intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
POSTING_READ(SPRSURF(pipe));
}
@@ -721,7 +721,7 @@ ilk_update_plane(struct drm_plane *plane,
I915_WRITE(DVSSCALE(pipe), dvsscale);
I915_WRITE(DVSCNTR(pipe), dvscntr);
I915_WRITE(DVSSURF(pipe),
- intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
+ intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
POSTING_READ(DVSSURF(pipe));
}
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index c6be35220955..c46bc8594f22 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -114,29 +114,3 @@ int intel_guc_sample_forcewake(struct intel_guc *guc)
return intel_guc_send(guc, action, ARRAY_SIZE(action));
}
-int intel_guc_log_flush_complete(struct intel_guc *guc)
-{
- u32 action[] = { INTEL_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE };
-
- return intel_guc_send(guc, action, ARRAY_SIZE(action));
-}
-
-int intel_guc_log_flush(struct intel_guc *guc)
-{
- u32 action[] = {
- INTEL_GUC_ACTION_FORCE_LOG_BUFFER_FLUSH,
- 0
- };
-
- return intel_guc_send(guc, action, ARRAY_SIZE(action));
-}
-
-int intel_guc_log_control(struct intel_guc *guc, u32 control_val)
-{
- u32 action[] = {
- INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING,
- control_val
- };
-
- return intel_guc_send(guc, action, ARRAY_SIZE(action));
-}
diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h
index 9490a8e049c3..d74f4d3ad8dc 100644
--- a/drivers/gpu/drm/i915/intel_uc.h
+++ b/drivers/gpu/drm/i915/intel_uc.h
@@ -93,29 +93,35 @@ struct i915_guc_client {
uint64_t submissions[I915_NUM_ENGINES];
};
-enum intel_guc_fw_status {
- GUC_FIRMWARE_FAIL = -1,
- GUC_FIRMWARE_NONE = 0,
- GUC_FIRMWARE_PENDING,
- GUC_FIRMWARE_SUCCESS
+enum intel_uc_fw_status {
+ INTEL_UC_FIRMWARE_FAIL = -1,
+ INTEL_UC_FIRMWARE_NONE = 0,
+ INTEL_UC_FIRMWARE_PENDING,
+ INTEL_UC_FIRMWARE_SUCCESS
+};
+
+enum intel_uc_fw_type {
+ INTEL_UC_FW_TYPE_GUC,
+ INTEL_UC_FW_TYPE_HUC
};
/*
* This structure encapsulates all the data needed during the process
* of fetching, caching, and loading the firmware image into the GuC.
*/
-struct intel_guc_fw {
- const char * guc_fw_path;
- size_t guc_fw_size;
- struct drm_i915_gem_object * guc_fw_obj;
- enum intel_guc_fw_status guc_fw_fetch_status;
- enum intel_guc_fw_status guc_fw_load_status;
-
- uint16_t guc_fw_major_wanted;
- uint16_t guc_fw_minor_wanted;
- uint16_t guc_fw_major_found;
- uint16_t guc_fw_minor_found;
-
+struct intel_uc_fw {
+ const char *path;
+ size_t size;
+ struct drm_i915_gem_object *obj;
+ enum intel_uc_fw_status fetch_status;
+ enum intel_uc_fw_status load_status;
+
+ uint16_t major_ver_wanted;
+ uint16_t minor_ver_wanted;
+ uint16_t major_ver_found;
+ uint16_t minor_ver_found;
+
+ enum intel_uc_fw_type fw;
uint32_t header_size;
uint32_t header_offset;
uint32_t rsa_size;
@@ -141,7 +147,7 @@ struct intel_guc_log {
};
struct intel_guc {
- struct intel_guc_fw guc_fw;
+ struct intel_uc_fw fw;
struct intel_guc_log log;
/* intel_guc_recv interrupt related state */
@@ -170,21 +176,28 @@ struct intel_guc {
struct mutex send_mutex;
};
+struct intel_huc {
+ /* Generic uC firmware management */
+ struct intel_uc_fw fw;
+
+ /* HuC-specific additions */
+};
+
/* intel_uc.c */
void intel_uc_init_early(struct drm_i915_private *dev_priv);
int intel_guc_send(struct intel_guc *guc, const u32 *action, u32 len);
int intel_guc_sample_forcewake(struct intel_guc *guc);
-int intel_guc_log_flush_complete(struct intel_guc *guc);
-int intel_guc_log_flush(struct intel_guc *guc);
-int intel_guc_log_control(struct intel_guc *guc, u32 control_val);
/* intel_guc_loader.c */
extern void intel_guc_init(struct drm_i915_private *dev_priv);
extern int intel_guc_setup(struct drm_i915_private *dev_priv);
extern void intel_guc_fini(struct drm_i915_private *dev_priv);
-extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status);
+extern const char *intel_uc_fw_status_repr(enum intel_uc_fw_status status);
extern int intel_guc_suspend(struct drm_i915_private *dev_priv);
extern int intel_guc_resume(struct drm_i915_private *dev_priv);
+void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
+ struct intel_uc_fw *uc_fw);
+u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv);
/* i915_guc_submission.c */
int i915_guc_submission_init(struct drm_i915_private *dev_priv);
@@ -193,10 +206,12 @@ int i915_guc_wq_reserve(struct drm_i915_gem_request *rq);
void i915_guc_wq_unreserve(struct drm_i915_gem_request *request);
void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
-void i915_guc_capture_logs(struct drm_i915_private *dev_priv);
-void i915_guc_flush_logs(struct drm_i915_private *dev_priv);
-void i915_guc_register(struct drm_i915_private *dev_priv);
-void i915_guc_unregister(struct drm_i915_private *dev_priv);
+struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size);
+
+/* intel_guc_log.c */
+void intel_guc_log_create(struct intel_guc *guc);
+void i915_guc_log_register(struct drm_i915_private *dev_priv);
+void i915_guc_log_unregister(struct drm_i915_private *dev_priv);
int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val);
static inline u32 guc_ggtt_offset(struct i915_vma *vma)
@@ -207,4 +222,10 @@ static inline u32 guc_ggtt_offset(struct i915_vma *vma)
return offset;
}
+/* intel_huc.c */
+void intel_huc_init(struct drm_i915_private *dev_priv);
+void intel_huc_fini(struct drm_i915_private *dev_priv);
+int intel_huc_load(struct drm_i915_private *dev_priv);
+void intel_guc_auth_huc(struct drm_i915_private *dev_priv);
+
#endif
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index 359cd2765552..f645275e6e63 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -207,8 +207,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct drm_encoder *encoder;
struct imx_hdmi *hdmi;
- struct resource *iores;
- int irq;
int ret;
if (!pdev->dev.of_node)
@@ -223,14 +221,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -ENXIO;
-
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
@@ -249,7 +239,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(pdev, encoder, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -264,7 +254,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
void *data)
{
- return dw_hdmi_unbind(dev, master, data);
+ return dw_hdmi_unbind(dev);
}
static const struct component_ops dw_hdmi_imx_ops = {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 01a21dd835b5..a73de1e669c2 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -170,8 +170,8 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
- struct mtk_drm_private *priv = drm->dev_private;
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+ struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base);
@@ -181,8 +181,8 @@ int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
{
- struct mtk_drm_private *priv = drm->dev_private;
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+ struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
mtk_ddp_comp_disable_vblank(ovl);
@@ -588,7 +588,6 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
goto unprepare;
drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE);
- priv->crtc[pipe] = &mtk_crtc->base;
priv->num_pipes++;
return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index aa9389446785..df322a7a5fcb 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -32,7 +32,6 @@ struct mtk_drm_private {
struct drm_device *drm;
struct device *dma_dev;
- struct drm_crtc *crtc[MAX_CRTC];
unsigned int num_pipes;
struct device_node *mutex_node;
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index 642b2fab42ff..a32d3b6e2e12 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -51,6 +51,9 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state;
struct drm_rect clip = { 0, };
+ if (!state->crtc)
+ return 0;
+
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index d836b2274531..f7c870172220 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -38,6 +38,11 @@
* - TV Panel encoding via ENCT
*/
+/* HHI Registers */
+#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
+#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */
+
struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
.mode_tag = MESON_VENC_MODE_CVBS_PAL,
.hso_begin = 3,
@@ -242,6 +247,20 @@ void meson_venc_disable_vsync(struct meson_drm *priv)
void meson_venc_init(struct meson_drm *priv)
{
+ /* Disable CVBS VDAC */
+ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
+
+ /* Power Down Dacs */
+ writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
+
+ /* Disable HDMI PHY */
+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
+
+ /* Disable HDMI */
+ writel_bits_relaxed(0x3, 0,
+ priv->io_base + _REG(VPU_HDMI_SETTING));
+
/* Disable all encoders */
writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index c809c085fd78..a2bcc70a03ef 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -167,7 +167,7 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder)
/* Disable CVBS VDAC */
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
}
static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c
index a1d8dd15b131..1ffdafea27e4 100644
--- a/drivers/gpu/drm/mga/mga_dma.c
+++ b/drivers/gpu/drm/mga/mga_dma.c
@@ -392,6 +392,24 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags)
drm_mga_private_t *dev_priv;
int ret;
+ /* There are PCI versions of the G450. These cards have the
+ * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
+ * bridge chip. We detect these cards, which are not currently
+ * supported by this driver, by looking at the device ID of the
+ * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the
+ * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
+ * device.
+ */
+ if ((dev->pdev->device == 0x0525) && dev->pdev->bus->self
+ && (dev->pdev->bus->self->vendor == 0x3388)
+ && (dev->pdev->bus->self->device == 0x0021)
+ && dev->agp) {
+ /* FIXME: This should be quirked in the pci core, but oh well
+ * the hw probably stopped existing. */
+ arch_phys_wc_del(dev->agp->agp_mtrr);
+ kfree(dev->agp);
+ dev->agp = NULL;
+ }
dev_priv = kzalloc(sizeof(drm_mga_private_t), GFP_KERNEL);
if (!dev_priv)
return -ENOMEM;
@@ -698,7 +716,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device *dev,
static int mga_do_dma_bootstrap(struct drm_device *dev,
drm_mga_dma_bootstrap_t *dma_bs)
{
- const int is_agp = (dma_bs->agp_mode != 0) && drm_pci_device_is_agp(dev);
+ const int is_agp = (dma_bs->agp_mode != 0) && dev->agp;
int err;
drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private;
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index 25b2a1a424e6..63ba0699d107 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -37,8 +37,6 @@
#include <drm/drm_pciids.h>
-static int mga_driver_device_is_agp(struct drm_device *dev);
-
static struct pci_device_id pciidlist[] = {
mga_PCI_IDS
};
@@ -66,7 +64,6 @@ static struct drm_driver driver = {
.lastclose = mga_driver_lastclose,
.set_busid = drm_pci_set_busid,
.dma_quiescent = mga_driver_dma_quiescent,
- .device_is_agp = mga_driver_device_is_agp,
.get_vblank_counter = mga_get_vblank_counter,
.enable_vblank = mga_enable_vblank,
.disable_vblank = mga_disable_vblank,
@@ -107,37 +104,3 @@ module_exit(mga_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
-
-/**
- * Determine if the device really is AGP or not.
- *
- * In addition to the usual tests performed by \c drm_device_is_agp, this
- * function detects PCI G450 cards that appear to the system exactly like
- * AGP G450 cards.
- *
- * \param dev The device to be tested.
- *
- * \returns
- * If the device is a PCI G450, zero is returned. Otherwise 2 is returned.
- */
-static int mga_driver_device_is_agp(struct drm_device *dev)
-{
- const struct pci_dev *const pdev = dev->pdev;
-
- /* There are PCI versions of the G450. These cards have the
- * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
- * bridge chip. We detect these cards, which are not currently
- * supported by this driver, by looking at the device ID of the
- * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the
- * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
- * device.
- */
-
- if ((pdev->device == 0x0525) && pdev->bus->self
- && (pdev->bus->self->vendor == 0x3388)
- && (pdev->bus->self->device == 0x0021)) {
- return 0;
- }
-
- return 2;
-}
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 5e20220ef4c6..657598bb1e6b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -236,8 +236,6 @@ struct ttm_bo_driver mgag200_bo_driver = {
.verify_access = mgag200_bo_verify_access,
.io_mem_reserve = &mgag200_ttm_io_mem_reserve,
.io_mem_free = &mgag200_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int mgag200_mm_init(struct mga_device *mdev)
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index d96b2b6898a3..7f78da695dff 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -4,6 +4,7 @@ config DRM_MSM
depends on DRM
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on OF && COMMON_CLK
+ depends on MMU
select REGULATOR
select DRM_KMS_HELPER
select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index a18126150e11..686a580c711a 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -213,7 +213,14 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
void adreno_flush(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- uint32_t wptr = get_wptr(gpu->rb);
+ uint32_t wptr;
+
+ /*
+ * Mask wptr value that we calculate to fit in the HW range. This is
+ * to account for the possibility that the last command fit exactly into
+ * the ringbuffer and rb->next hasn't wrapped to zero yet
+ */
+ wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1);
/* ensure writes to ringbuffer have hit system memory: */
mb();
@@ -338,7 +345,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
{
struct adreno_platform_config *config = pdev->dev.platform_data;
struct msm_gpu *gpu = &adreno_gpu->base;
- struct msm_mmu *mmu;
int ret;
adreno_gpu->funcs = funcs;
@@ -378,8 +384,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
return ret;
}
- mmu = gpu->aspace->mmu;
- if (mmu) {
+ if (gpu->aspace && gpu->aspace->mmu) {
+ struct msm_mmu *mmu = gpu->aspace->mmu;
ret = mmu->funcs->attach(mmu, iommu_ports,
ARRAY_SIZE(iommu_ports));
if (ret)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 5f6cd8745dbc..c396d459a9d0 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -119,13 +119,7 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{
- int i;
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
- struct drm_plane *plane;
- struct drm_plane_state *plane_state;
-
- for_each_plane_in_state(state, plane, plane_state, i)
- mdp5_plane_complete_commit(plane, plane_state);
if (mdp5_kms->smp)
mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 17b0cc101171..cdfc63d90c7b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -104,8 +104,6 @@ struct mdp5_plane_state {
/* assigned by crtc blender */
enum mdp_mixer_stage_id stage;
-
- bool pending : 1;
};
#define to_mdp5_plane_state(x) \
container_of(x, struct mdp5_plane_state, base)
@@ -232,8 +230,6 @@ int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
-void mdp5_plane_complete_commit(struct drm_plane *plane,
- struct drm_plane_state *state);
enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 75247ea4335b..b9fb111d3428 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -179,7 +179,6 @@ mdp5_plane_atomic_print_state(struct drm_printer *p,
drm_printf(p, "\tzpos=%u\n", pstate->zpos);
drm_printf(p, "\talpha=%u\n", pstate->alpha);
drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
- drm_printf(p, "\tpending=%u\n", pstate->pending);
}
static void mdp5_plane_reset(struct drm_plane *plane)
@@ -220,8 +219,6 @@ mdp5_plane_duplicate_state(struct drm_plane *plane)
if (mdp5_state && mdp5_state->base.fb)
drm_framebuffer_reference(mdp5_state->base.fb);
- mdp5_state->pending = false;
-
return &mdp5_state->base;
}
@@ -288,13 +285,6 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
DBG("%s: check (%d -> %d)", plane->name,
plane_enabled(old_state), plane_enabled(state));
- /* We don't allow faster-than-vblank updates.. if we did add this
- * some day, we would need to disallow in cases where hwpipe
- * changes
- */
- if (WARN_ON(to_mdp5_plane_state(old_state)->pending))
- return -EBUSY;
-
max_width = config->hw->lm.max_width << 16;
max_height = config->hw->lm.max_height << 16;
@@ -370,12 +360,9 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = plane->state;
- struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
DBG("%s: update", plane->name);
- mdp5_state->pending = true;
-
if (plane_enabled(state)) {
int ret;
@@ -851,15 +838,6 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
return pstate->hwpipe->flush_mask;
}
-/* called after vsync in thread context */
-void mdp5_plane_complete_commit(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-
- pstate->pending = false;
-}
-
/* initialize plane */
struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary)
{
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 5d68ab362d75..f8a587eac6b8 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -174,10 +174,8 @@ fail_unlock:
fail:
if (ret) {
- if (fb) {
- drm_framebuffer_unregister_private(fb);
+ if (fb)
drm_framebuffer_remove(fb);
- }
}
return ret;
@@ -247,7 +245,6 @@ void msm_fbdev_free(struct drm_device *dev)
/* this will free the backing object */
if (fbdev->fb) {
msm_gem_put_vaddr(fbdev->bo);
- drm_framebuffer_unregister_private(fbdev->fb);
drm_framebuffer_remove(fbdev->fb);
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index d8bc59c7e261..8098677a3916 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -294,6 +294,8 @@ put_iova(struct drm_gem_object *obj)
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
+ if (!priv->aspace[id])
+ continue;
msm_gem_unmap_vma(priv->aspace[id],
&msm_obj->domain[id], msm_obj->sgt);
}
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 166e84e4f0d4..489676568a10 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -106,7 +106,8 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
pagefault_disable();
}
- if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+ if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
+ !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
ret = -EINVAL;
goto out_unlock;
@@ -290,7 +291,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
{
uint32_t i, last_offset = 0;
uint32_t *ptr;
- int ret;
+ int ret = 0;
if (offset % 4) {
DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
@@ -318,12 +319,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
if (ret)
- return -EFAULT;
+ goto out;
if (submit_reloc.submit_offset % 4) {
DRM_ERROR("non-aligned reloc offset: %u\n",
submit_reloc.submit_offset);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* offset in dwords: */
@@ -332,12 +334,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
if ((off >= (obj->base.size / 4)) ||
(off < last_offset)) {
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid);
if (ret)
- return ret;
+ goto out;
if (valid)
continue;
@@ -354,9 +357,10 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
last_offset = off;
}
+out:
msm_gem_put_vaddr_locked(&obj->base);
- return 0;
+ return ret;
}
static void submit_cleanup(struct msm_gem_submit *submit)
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index f326cf6a32e6..67b34e069abf 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -23,7 +23,8 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size)
struct msm_ringbuffer *ring;
int ret;
- size = ALIGN(size, 4); /* size should be dword aligned */
+ if (WARN_ON(!is_power_of_2(size)))
+ return ERR_PTR(-EINVAL);
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 7bd4683216d0..4df4f6ed4886 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -199,7 +199,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
if (!nvxx_device(device)->func->pci)
getparam->value = 3;
else
- if (drm_pci_device_is_agp(dev))
+ if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
getparam->value = 0;
else
if (!pci_is_pcie(dev->pdev))
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index dd07ca140d12..8a528ebe30f3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1194,7 +1194,8 @@ out:
}
static void
-nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
+nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
+ struct ttm_mem_reg *new_mem)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nvkm_vma *vma;
@@ -1570,8 +1571,6 @@ struct ttm_bo_driver nouveau_bo_driver = {
.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
.io_mem_free = &nouveau_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
struct nvkm_vma *
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index add353e230f4..6b570079d185 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -58,27 +58,30 @@ int
nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
{
struct drm_crtc *crtc;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (nv_crtc->index == pipe) {
- nvif_notify_get(&nv_crtc->vblank);
- return 0;
- }
- }
- return -EINVAL;
+ struct nouveau_crtc *nv_crtc;
+
+ crtc = drm_crtc_from_index(dev, pipe);
+ if (!crtc)
+ return -EINVAL;
+
+ nv_crtc = nouveau_crtc(crtc);
+ nvif_notify_get(&nv_crtc->vblank);
+
+ return 0;
}
void
nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
{
struct drm_crtc *crtc;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (nv_crtc->index == pipe) {
- nvif_notify_put(&nv_crtc->vblank);
- return;
- }
- }
+ struct nouveau_crtc *nv_crtc;
+
+ crtc = drm_crtc_from_index(dev, pipe);
+ if (!crtc)
+ return;
+
+ nv_crtc = nouveau_crtc(crtc);
+ nvif_notify_put(&nv_crtc->vblank);
}
static inline int
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index cb85cb72dc1c..452da483ca01 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -3417,7 +3417,7 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
mstm->outp = outp;
mstm->mgr.cbs = &nv50_mstm;
- ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max,
+ ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max,
max_payloads, conn_base_id);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c
index bf65862daf62..19b716745623 100644
--- a/drivers/gpu/drm/omapdrm/omap_debugfs.c
+++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c
@@ -123,13 +123,4 @@ int omap_debugfs_init(struct drm_minor *minor)
return ret;
}
-void omap_debugfs_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(omap_debugfs_list,
- ARRAY_SIZE(omap_debugfs_list), minor);
- if (dmm_is_available())
- drm_debugfs_remove_files(omap_dmm_debugfs_list,
- ARRAY_SIZE(omap_dmm_debugfs_list), minor);
-}
-
#endif
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 00aa214b7560..afe8f05b927b 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -719,7 +719,6 @@ static struct drm_driver omap_drm_driver = {
.disable_vblank = omap_irq_disable_vblank,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = omap_debugfs_init,
- .debugfs_cleanup = omap_debugfs_cleanup,
#endif
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index b20377efd01b..36d93ce84a29 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -103,7 +103,6 @@ struct omap_drm_private {
#ifdef CONFIG_DEBUG_FS
int omap_debugfs_init(struct drm_minor *minor);
-void omap_debugfs_cleanup(struct drm_minor *minor);
void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index aed99a0fc44b..2a839956dae6 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -225,10 +225,8 @@ fail:
drm_fb_helper_release_fbi(helper);
- if (fb) {
- drm_framebuffer_unregister_private(fb);
+ if (fb)
drm_framebuffer_remove(fb);
- }
}
return ret;
@@ -314,10 +312,8 @@ void omap_fbdev_free(struct drm_device *dev)
omap_gem_put_paddr(fbdev->bo);
/* this will free the backing object */
- if (fbdev->fb) {
- drm_framebuffer_unregister_private(fbdev->fb);
+ if (fbdev->fb)
drm_framebuffer_remove(fbdev->fb);
- }
kfree(fbdev);
diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c
index 241af9131dc8..057b2b547cac 100644
--- a/drivers/gpu/drm/qxl/qxl_debugfs.c
+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c
@@ -84,8 +84,18 @@ int
qxl_debugfs_init(struct drm_minor *minor)
{
#if defined(CONFIG_DEBUG_FS)
+ int r;
+ struct qxl_device *dev =
+ (struct qxl_device *) minor->dev->dev_private;
+
drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
+
+ r = qxl_ttm_debugfs_init(dev);
+ if (r) {
+ DRM_ERROR("Failed to init TTM debugfs\n");
+ return r;
+ }
#endif
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 659c77742649..416ade8566b7 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -1077,7 +1077,6 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
dev->mode_config.suggested_x_property, 0);
drm_object_attach_property(&connector->base,
dev->mode_config.suggested_y_property, 0);
- drm_connector_register(connector);
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 460bbceae297..6e0f8a2d8ac9 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -62,20 +62,83 @@ static struct pci_driver qxl_pci_driver;
static int
qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ struct drm_device *drm;
+ struct qxl_device *qdev;
+ int ret;
+
if (pdev->revision < 4) {
DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
" use xf86-video-qxl in user mode");
return -EINVAL; /* TODO: ENODEV ? */
}
- return drm_get_pci_dev(pdev, ent, &qxl_driver);
+
+ drm = drm_dev_alloc(&qxl_driver, &pdev->dev);
+ if (IS_ERR(drm))
+ return -ENOMEM;
+
+ qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
+ if (!qdev) {
+ ret = -ENOMEM;
+ goto free_drm_device;
+ }
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto free_drm_device;
+
+ drm->pdev = pdev;
+ pci_set_drvdata(pdev, drm);
+ drm->dev_private = qdev;
+
+ ret = qxl_device_init(qdev, drm, pdev, ent->driver_data);
+ if (ret)
+ goto disable_pci;
+
+ ret = drm_vblank_init(drm, 1);
+ if (ret)
+ goto unload;
+
+ ret = qxl_modeset_init(qdev);
+ if (ret)
+ goto vblank_cleanup;
+
+ drm_kms_helper_poll_init(qdev->ddev);
+
+ /* Complete initialization. */
+ ret = drm_dev_register(drm, ent->driver_data);
+ if (ret)
+ goto modeset_cleanup;
+
+ return 0;
+
+modeset_cleanup:
+ qxl_modeset_fini(qdev);
+vblank_cleanup:
+ drm_vblank_cleanup(drm);
+unload:
+ qxl_device_fini(qdev);
+disable_pci:
+ pci_disable_device(pdev);
+free_drm_device:
+ kfree(qdev);
+ kfree(drm);
+ return ret;
}
static void
qxl_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
+ struct qxl_device *qdev = dev->dev_private;
+
+ drm_dev_unregister(dev);
+
+ qxl_modeset_fini(qdev);
+ qxl_device_fini(qdev);
- drm_put_dev(dev);
+ dev->dev_private = NULL;
+ kfree(qdev);
+ drm_dev_unref(dev);
}
static const struct file_operations qxl_fops = {
@@ -230,8 +293,6 @@ static struct pci_driver qxl_pci_driver = {
static struct drm_driver qxl_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
- .load = qxl_driver_load,
- .unload = qxl_driver_unload,
.get_vblank_counter = qxl_noop_get_vblank_counter,
.enable_vblank = qxl_noop_enable_vblank,
.disable_vblank = qxl_noop_disable_vblank,
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 883d8639c04e..0d877fa61162 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -336,8 +336,9 @@ __printf(2,3) void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...);
extern const struct drm_ioctl_desc qxl_ioctls[];
extern int qxl_max_ioctl;
-int qxl_driver_load(struct drm_device *dev, unsigned long flags);
-void qxl_driver_unload(struct drm_device *dev);
+int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev,
+ struct pci_dev *pdev, unsigned long flags);
+void qxl_device_fini(struct qxl_device *qdev);
int qxl_modeset_init(struct qxl_device *qdev);
void qxl_modeset_fini(struct qxl_device *qdev);
@@ -531,6 +532,7 @@ int qxl_garbage_collect(struct qxl_device *qdev);
int qxl_debugfs_init(struct drm_minor *minor);
void qxl_debugfs_takedown(struct drm_minor *minor);
+int qxl_ttm_debugfs_init(struct qxl_device *qdev);
/* qxl_prime.c */
int qxl_gem_prime_pin(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index b2491407b616..d0666f5dccd6 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -115,7 +115,7 @@ static void qxl_gc_work(struct work_struct *work)
qxl_garbage_collect(qdev);
}
-static int qxl_device_init(struct qxl_device *qdev,
+int qxl_device_init(struct qxl_device *qdev,
struct drm_device *ddev,
struct pci_dev *pdev,
unsigned long flags)
@@ -263,7 +263,7 @@ static int qxl_device_init(struct qxl_device *qdev,
return 0;
}
-static void qxl_device_fini(struct qxl_device *qdev)
+void qxl_device_fini(struct qxl_device *qdev)
{
if (qdev->current_release_bo[0])
qxl_bo_unref(&qdev->current_release_bo[0]);
@@ -284,55 +284,3 @@ static void qxl_device_fini(struct qxl_device *qdev)
qdev->mode_info.num_modes = 0;
qxl_debugfs_remove_files(qdev);
}
-
-void qxl_driver_unload(struct drm_device *dev)
-{
- struct qxl_device *qdev = dev->dev_private;
-
- if (qdev == NULL)
- return;
-
- drm_vblank_cleanup(dev);
-
- qxl_modeset_fini(qdev);
- qxl_device_fini(qdev);
-
- kfree(qdev);
- dev->dev_private = NULL;
-}
-
-int qxl_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct qxl_device *qdev;
- int r;
-
- qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
- if (qdev == NULL)
- return -ENOMEM;
-
- dev->dev_private = qdev;
-
- r = qxl_device_init(qdev, dev, dev->pdev, flags);
- if (r)
- goto out;
-
- r = drm_vblank_init(dev, 1);
- if (r)
- goto unload;
-
- r = qxl_modeset_init(qdev);
- if (r)
- goto unload;
-
- drm_kms_helper_poll_init(qdev->ddev);
-
- return 0;
-unload:
- qxl_driver_unload(dev);
-
-out:
- kfree(qdev);
- return r;
-}
-
-
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 1b096c5252ad..3dcc48431015 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -35,7 +35,6 @@
#include "qxl_object.h"
#include <linux/delay.h>
-static int qxl_ttm_debugfs_init(struct qxl_device *qdev);
static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
{
@@ -367,6 +366,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo,
}
static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
+ bool evict,
struct ttm_mem_reg *new_mem)
{
struct qxl_bo *qbo;
@@ -394,8 +394,6 @@ static struct ttm_bo_driver qxl_bo_driver = {
.io_mem_reserve = &qxl_ttm_io_mem_reserve,
.io_mem_free = &qxl_ttm_io_mem_free,
.move_notify = &qxl_bo_move_notify,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int qxl_ttm_init(struct qxl_device *qdev)
@@ -436,11 +434,6 @@ int qxl_ttm_init(struct qxl_device *qdev)
((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
DRM_INFO("qxl: %uM of Surface memory size\n",
(unsigned)qdev->surfaceram_size / (1024 * 1024));
- r = qxl_ttm_debugfs_init(qdev);
- if (r) {
- DRM_ERROR("Failed to init debugfs\n");
- return r;
- }
return 0;
}
@@ -473,7 +466,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data)
}
#endif
-static int qxl_ttm_debugfs_init(struct qxl_device *qdev)
+int qxl_ttm_debugfs_init(struct qxl_device *qdev)
{
#if defined(CONFIG_DEBUG_FS)
static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index c829cfb02fc4..00cfb5d2875f 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -596,52 +596,58 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
#ifdef CONFIG_ACPI
static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
{
- bool ret = false;
struct acpi_table_header *hdr;
acpi_size tbl_size;
UEFI_ACPI_VFCT *vfct;
- GOP_VBIOS_CONTENT *vbios;
- VFCT_IMAGE_HEADER *vhdr;
+ unsigned offset;
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
- goto out_unmap;
+ return false;
}
vfct = (UEFI_ACPI_VFCT *)hdr;
- if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
- DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
- goto out_unmap;
- }
+ offset = vfct->VBIOSImageOffset;
- vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
- vhdr = &vbios->VbiosHeader;
- DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
- vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
- vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
-
- if (vhdr->PCIBus != rdev->pdev->bus->number ||
- vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) ||
- vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) ||
- vhdr->VendorID != rdev->pdev->vendor ||
- vhdr->DeviceID != rdev->pdev->device) {
- DRM_INFO("ACPI VFCT table is not for this card\n");
- goto out_unmap;
- }
+ while (offset < tbl_size) {
+ GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
+ VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
- if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
- DRM_ERROR("ACPI VFCT image truncated\n");
- goto out_unmap;
- }
+ offset += sizeof(VFCT_IMAGE_HEADER);
+ if (offset > tbl_size) {
+ DRM_ERROR("ACPI VFCT image header truncated\n");
+ return false;
+ }
- rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
- ret = !!rdev->bios;
+ offset += vhdr->ImageLength;
+ if (offset > tbl_size) {
+ DRM_ERROR("ACPI VFCT image truncated\n");
+ return false;
+ }
+
+ if (vhdr->ImageLength &&
+ vhdr->PCIBus == rdev->pdev->bus->number &&
+ vhdr->PCIDevice == PCI_SLOT(rdev->pdev->devfn) &&
+ vhdr->PCIFunction == PCI_FUNC(rdev->pdev->devfn) &&
+ vhdr->VendorID == rdev->pdev->vendor &&
+ vhdr->DeviceID == rdev->pdev->device) {
+ rdev->bios = kmemdup(&vbios->VbiosContent,
+ vhdr->ImageLength,
+ GFP_KERNEL);
+
+ if (!rdev->bios) {
+ kfree(rdev->bios);
+ return false;
+ }
+ return true;
+ }
+ }
-out_unmap:
- return ret;
+ DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
+ return false;
}
#else
static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 510ea371dacc..a8442f7196d6 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -121,7 +121,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
VRAM, also but everything into VRAM on AGP cards and older
IGP chips to avoid image corruptions */
if (p->ring == R600_RING_TYPE_UVD_INDEX &&
- (i == 0 || drm_pci_device_is_agp(p->rdev->ddev) ||
+ (i == 0 || pci_find_capability(p->rdev->ddev->pdev,
+ PCI_CAP_ID_AGP) ||
p->rdev->family == CHIP_RS780 ||
p->rdev->family == CHIP_RS880)) {
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 8a1df2a1afbd..4b0c388be3f5 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1549,8 +1549,6 @@ failed:
return r;
}
-static void radeon_debugfs_remove_files(struct radeon_device *rdev);
-
/**
* radeon_device_fini - tear down the driver
*
@@ -1577,7 +1575,6 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->rmmio = NULL;
if (rdev->family >= CHIP_BONAIRE)
radeon_doorbell_fini(rdev);
- radeon_debugfs_remove_files(rdev);
}
@@ -1954,16 +1951,3 @@ int radeon_debugfs_add_files(struct radeon_device *rdev,
#endif
return 0;
}
-
-static void radeon_debugfs_remove_files(struct radeon_device *rdev)
-{
-#if defined(CONFIG_DEBUG_FS)
- unsigned i;
-
- for (i = 0; i < rdev->debugfs_count; i++) {
- drm_debugfs_remove_files(rdev->debugfs[i].files,
- rdev->debugfs[i].num_files,
- rdev->ddev->primary);
- }
-#endif
-}
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
index 6d1237d6e1b8..7d5ada3980dc 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -667,7 +667,7 @@ radeon_dp_mst_init(struct radeon_connector *radeon_connector)
return 0;
radeon_connector->mst_mgr.cbs = &mst_cbs;
- return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev,
+ return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev,
&radeon_connector->ddc_bus->aux, 16, 6,
radeon_connector->base.base.id);
}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 116cf0d23595..56f35c06742c 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -105,7 +105,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
dev->dev_private = (void *)rdev;
/* update BUS flag */
- if (drm_pci_device_is_agp(dev)) {
+ if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP)) {
flags |= RADEON_IS_AGP;
} else if (pci_is_pcie(dev->pdev)) {
flags |= RADEON_IS_PCIE;
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 41b72ce6613f..74b276060c20 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -765,6 +765,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
}
void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+ bool evict,
struct ttm_mem_reg *new_mem)
{
struct radeon_bo *rbo;
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index a10bb3deee54..9ffd8215d38a 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -150,6 +150,7 @@ extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
bool force_drop);
extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+ bool evict,
struct ttm_mem_reg *new_mem);
extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 1888144d0fed..7a10b3852970 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -502,6 +502,8 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
mem->bus.addr =
ioremap_nocache(mem->bus.base + mem->bus.offset,
mem->bus.size);
+ if (!mem->bus.addr)
+ return -ENOMEM;
/*
* Alpha: Use just the bus offset plus
@@ -871,8 +873,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
.fault_reserve_notify = &radeon_bo_fault_reserve_notify,
.io_mem_reserve = &radeon_ttm_io_mem_reserve,
.io_mem_free = &radeon_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int radeon_ttm_init(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index ad4d7b8b8322..414776811e71 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -50,7 +50,6 @@ MODULE_FIRMWARE("radeon/tahiti_ce.bin");
MODULE_FIRMWARE("radeon/tahiti_mc.bin");
MODULE_FIRMWARE("radeon/tahiti_rlc.bin");
MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
@@ -115,6 +114,9 @@ MODULE_FIRMWARE("radeon/hainan_mc.bin");
MODULE_FIRMWARE("radeon/hainan_rlc.bin");
MODULE_FIRMWARE("radeon/hainan_smc.bin");
MODULE_FIRMWARE("radeon/hainan_k_smc.bin");
+MODULE_FIRMWARE("radeon/banks_k_2_smc.bin");
+
+MODULE_FIRMWARE("radeon/si58_mc.bin");
static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh);
static void si_pcie_gen3_enable(struct radeon_device *rdev);
@@ -1651,15 +1653,14 @@ static int si_init_microcode(struct radeon_device *rdev)
int err;
int new_fw = 0;
bool new_smc = false;
+ bool si58_fw = false;
+ bool banks2_fw = false;
DRM_DEBUG("\n");
switch (rdev->family) {
case CHIP_TAHITI:
chip_name = "TAHITI";
- /* XXX: figure out which Tahitis need the new ucode */
- if (0)
- new_smc = true;
new_chip_name = "tahiti";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
me_req_size = SI_PM4_UCODE_SIZE * 4;
@@ -1671,12 +1672,9 @@ static int si_init_microcode(struct radeon_device *rdev)
break;
case CHIP_PITCAIRN:
chip_name = "PITCAIRN";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->device == 0x6810) ||
- (rdev->pdev->device == 0x6811) ||
- (rdev->pdev->device == 0x6816) ||
- (rdev->pdev->device == 0x6817) ||
- (rdev->pdev->device == 0x6806))
+ if ((rdev->pdev->revision == 0x81) &&
+ ((rdev->pdev->device == 0x6810) ||
+ (rdev->pdev->device == 0x6811)))
new_smc = true;
new_chip_name = "pitcairn";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1689,15 +1687,15 @@ static int si_init_microcode(struct radeon_device *rdev)
break;
case CHIP_VERDE:
chip_name = "VERDE";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6820) ||
- (rdev->pdev->device == 0x6821) ||
- (rdev->pdev->device == 0x6822) ||
- (rdev->pdev->device == 0x6823) ||
- (rdev->pdev->device == 0x682A) ||
- (rdev->pdev->device == 0x682B))
+ if (((rdev->pdev->device == 0x6820) &&
+ ((rdev->pdev->revision == 0x81) ||
+ (rdev->pdev->revision == 0x83))) ||
+ ((rdev->pdev->device == 0x6821) &&
+ ((rdev->pdev->revision == 0x83) ||
+ (rdev->pdev->revision == 0x87))) ||
+ ((rdev->pdev->revision == 0x87) &&
+ ((rdev->pdev->device == 0x6823) ||
+ (rdev->pdev->device == 0x682b))))
new_smc = true;
new_chip_name = "verde";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1710,13 +1708,13 @@ static int si_init_microcode(struct radeon_device *rdev)
break;
case CHIP_OLAND:
chip_name = "OLAND";
- if ((rdev->pdev->revision == 0xC7) ||
- (rdev->pdev->revision == 0x80) ||
- (rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6604) ||
- (rdev->pdev->device == 0x6605))
+ if (((rdev->pdev->revision == 0x81) &&
+ ((rdev->pdev->device == 0x6600) ||
+ (rdev->pdev->device == 0x6604) ||
+ (rdev->pdev->device == 0x6605) ||
+ (rdev->pdev->device == 0x6610))) ||
+ ((rdev->pdev->revision == 0x83) &&
+ (rdev->pdev->device == 0x6610)))
new_smc = true;
new_chip_name = "oland";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
@@ -1728,13 +1726,17 @@ static int si_init_microcode(struct radeon_device *rdev)
break;
case CHIP_HAINAN:
chip_name = "HAINAN";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0xC3) ||
- (rdev->pdev->device == 0x6664) ||
- (rdev->pdev->device == 0x6665) ||
- (rdev->pdev->device == 0x6667))
+ if (((rdev->pdev->revision == 0x81) &&
+ (rdev->pdev->device == 0x6660)) ||
+ ((rdev->pdev->revision == 0x83) &&
+ ((rdev->pdev->device == 0x6660) ||
+ (rdev->pdev->device == 0x6663) ||
+ (rdev->pdev->device == 0x6665) ||
+ (rdev->pdev->device == 0x6667))))
new_smc = true;
+ else if ((rdev->pdev->revision == 0xc3) &&
+ (rdev->pdev->device == 0x6665))
+ banks2_fw = true;
new_chip_name = "hainan";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
me_req_size = SI_PM4_UCODE_SIZE * 4;
@@ -1746,6 +1748,10 @@ static int si_init_microcode(struct radeon_device *rdev)
default: BUG();
}
+ /* this memory configuration requires special firmware */
+ if (((RREG32(MC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58)
+ si58_fw = true;
+
DRM_INFO("Loading %s Microcode\n", new_chip_name);
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name);
@@ -1849,7 +1855,10 @@ static int si_init_microcode(struct radeon_device *rdev)
}
}
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name);
+ if (si58_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin");
+ else
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name);
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev);
if (err) {
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);
@@ -1880,7 +1889,9 @@ static int si_init_microcode(struct radeon_device *rdev)
}
}
- if (new_smc)
+ if (banks2_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/banks_k_2_smc.bin");
+ else if (new_smc)
snprintf(fw_name, sizeof(fw_name), "radeon/%s_k_smc.bin", new_chip_name);
else
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 8b5e697f2549..d12b8978142f 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2912,29 +2912,6 @@ static int si_init_smc_spll_table(struct radeon_device *rdev)
return ret;
}
-struct si_dpm_quirk {
- u32 chip_vendor;
- u32 chip_device;
- u32 subsys_vendor;
- u32 subsys_device;
- u32 max_sclk;
- u32 max_mclk;
-};
-
-/* cards with dpm stability problems */
-static struct si_dpm_quirk si_dpm_quirk_list[] = {
- /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
- { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 },
- { PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 },
- { 0, 0, 0, 0 },
-};
-
static u16 si_get_lower_of_leakage_and_vce_voltage(struct radeon_device *rdev,
u16 vce_voltage)
{
@@ -2997,42 +2974,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
u32 max_sclk = 0, max_mclk = 0;
int i;
- struct si_dpm_quirk *p = si_dpm_quirk_list;
- /* limit all SI kickers */
- if (rdev->family == CHIP_PITCAIRN) {
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->device == 0x6810) ||
- (rdev->pdev->device == 0x6811) ||
- (rdev->pdev->device == 0x6816) ||
- (rdev->pdev->device == 0x6817) ||
- (rdev->pdev->device == 0x6806))
- max_mclk = 120000;
- } else if (rdev->family == CHIP_VERDE) {
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6820) ||
- (rdev->pdev->device == 0x6821) ||
- (rdev->pdev->device == 0x6822) ||
- (rdev->pdev->device == 0x6823) ||
- (rdev->pdev->device == 0x682A) ||
- (rdev->pdev->device == 0x682B)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (rdev->family == CHIP_OLAND) {
- if ((rdev->pdev->revision == 0xC7) ||
- (rdev->pdev->revision == 0x80) ||
- (rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6604) ||
- (rdev->pdev->device == 0x6605)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (rdev->family == CHIP_HAINAN) {
+ if (rdev->family == CHIP_HAINAN) {
if ((rdev->pdev->revision == 0x81) ||
(rdev->pdev->revision == 0x83) ||
(rdev->pdev->revision == 0xC3) ||
@@ -3040,20 +2983,7 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
(rdev->pdev->device == 0x6665) ||
(rdev->pdev->device == 0x6667)) {
max_sclk = 75000;
- max_mclk = 80000;
- }
- }
- /* Apply dpm quirks */
- while (p && p->chip_device != 0) {
- if (rdev->pdev->vendor == p->chip_vendor &&
- rdev->pdev->device == p->chip_device &&
- rdev->pdev->subsystem_vendor == p->subsys_vendor &&
- rdev->pdev->subsystem_device == p->subsys_device) {
- max_sclk = p->max_sclk;
- max_mclk = p->max_mclk;
- break;
}
- ++p;
}
if (rps->vce_active) {
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 0665fb915579..a6d4a0236e8f 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -257,8 +257,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct drm_encoder *encoder;
struct rockchip_hdmi *hdmi;
- struct resource *iores;
- int irq;
int ret;
if (!pdev->dev.of_node)
@@ -273,14 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -ENXIO;
-
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
@@ -301,7 +291,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(pdev, encoder, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -316,7 +306,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
void *data)
{
- return dw_hdmi_unbind(dev, master, data);
+ return dw_hdmi_unbind(dev);
}
static const struct component_ops dw_hdmi_rockchip_ops = {
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c
index 6d2a5cd211f3..6df53e6c1308 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -1274,13 +1274,19 @@ static bool evict_everything(struct drm_mm *mm,
if (drm_mm_scan_add_block(&scan, &e->node))
break;
}
+
+ err = 0;
list_for_each_entry(e, &evict_list, link) {
if (!drm_mm_scan_remove_block(&scan, &e->node)) {
- pr_err("Node %lld not marked for eviction!\n",
- e->node.start);
- list_del(&e->link);
+ if (!err) {
+ pr_err("Node %lld not marked for eviction!\n",
+ e->node.start);
+ err = -EINVAL;
+ }
}
}
+ if (err)
+ return false;
list_for_each_entry(e, &evict_list, link)
drm_mm_remove_node(&e->node);
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 278a63f10d9f..acc056644cd0 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -89,38 +89,9 @@ static struct drm_info_list sti_drm_dbg_list[] = {
{"fps_get", sti_drm_fps_dbg_show, 0},
};
-static int sti_drm_debugfs_create(struct dentry *root,
- struct drm_minor *minor,
- const char *name,
- const struct file_operations *fops)
-{
- struct drm_device *dev = minor->dev;
- struct drm_info_node *node;
- struct dentry *ent;
-
- ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, fops);
- if (IS_ERR(ent))
- return PTR_ERR(ent);
-
- node = kmalloc(sizeof(*node), GFP_KERNEL);
- if (!node) {
- debugfs_remove(ent);
- return -ENOMEM;
- }
-
- node->minor = minor;
- node->dent = ent;
- node->info_ent = (void *)fops;
-
- mutex_lock(&minor->debugfs_lock);
- list_add(&node->list, &minor->debugfs_list);
- mutex_unlock(&minor->debugfs_lock);
-
- return 0;
-}
-
static int sti_drm_dbg_init(struct drm_minor *minor)
{
+ struct dentry *dentry;
int ret;
ret = drm_debugfs_create_files(sti_drm_dbg_list,
@@ -129,10 +100,13 @@ static int sti_drm_dbg_init(struct drm_minor *minor)
if (ret)
goto err;
- ret = sti_drm_debugfs_create(minor->debugfs_root, minor, "fps_show",
+ dentry = debugfs_create_file("fps_show", S_IRUGO | S_IWUSR,
+ minor->debugfs_root, minor->dev,
&sti_drm_fps_fops);
- if (ret)
+ if (!dentry) {
+ ret = -ENOMEM;
goto err;
+ }
DRM_INFO("%s: debugfs installed\n", DRIVER_NAME);
return 0;
@@ -141,15 +115,6 @@ err:
return ret;
}
-static void sti_drm_dbg_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(sti_drm_dbg_list,
- ARRAY_SIZE(sti_drm_dbg_list), minor);
-
- drm_debugfs_remove_files((struct drm_info_list *)&sti_drm_fps_fops,
- 1, minor);
-}
-
static void sti_atomic_schedule(struct sti_private *private,
struct drm_atomic_state *state)
{
@@ -314,7 +279,6 @@ static struct drm_driver sti_driver = {
.gem_prime_mmap = drm_gem_cma_prime_mmap,
.debugfs_init = sti_drm_dbg_init,
- .debugfs_cleanup = sti_drm_dbg_cleanup,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index 411dc6ec976e..bb23318a44b7 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -195,13 +195,6 @@ static struct drm_info_list dvo_debugfs_files[] = {
{ "dvo", dvo_dbg_show, 0, NULL },
};
-static void dvo_debugfs_exit(struct sti_dvo *dvo, struct drm_minor *minor)
-{
- drm_debugfs_remove_files(dvo_debugfs_files,
- ARRAY_SIZE(dvo_debugfs_files),
- minor);
-}
-
static int dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor)
{
unsigned int i;
@@ -514,9 +507,6 @@ static void sti_dvo_unbind(struct device *dev,
struct device *master, void *data)
{
struct sti_dvo *dvo = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
-
- dvo_debugfs_exit(dvo, drm_dev->primary);
drm_bridge_remove(dvo->bridge);
}
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 66d37d78152a..0c0a75bc8bc3 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -365,13 +365,6 @@ static struct drm_info_list hda_debugfs_files[] = {
{ "hda", hda_dbg_show, 0, NULL },
};
-static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor)
-{
- drm_debugfs_remove_files(hda_debugfs_files,
- ARRAY_SIZE(hda_debugfs_files),
- minor);
-}
-
static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor)
{
unsigned int i;
@@ -739,10 +732,6 @@ err_sysfs:
static void sti_hda_unbind(struct device *dev,
struct device *master, void *data)
{
- struct sti_hda *hda = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
-
- hda_debugfs_exit(hda, drm_dev->primary);
}
static const struct component_ops sti_hda_ops = {
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 5ef1d1fce6d1..c9151849d604 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -731,13 +731,6 @@ static struct drm_info_list hdmi_debugfs_files[] = {
{ "hdmi", hdmi_dbg_show, 0, NULL },
};
-static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor)
-{
- drm_debugfs_remove_files(hdmi_debugfs_files,
- ARRAY_SIZE(hdmi_debugfs_files),
- minor);
-}
-
static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
{
unsigned int i;
@@ -1356,10 +1349,6 @@ err_sysfs:
static void sti_hdmi_unbind(struct device *dev,
struct device *master, void *data)
{
- struct sti_hdmi *hdmi = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
-
- hdmi_debugfs_exit(hdmi, drm_dev->primary);
}
static const struct component_ops sti_hdmi_ops = {
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 699094c559b4..427d8f58c6b1 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -73,7 +73,7 @@ void sti_plane_update_fps(struct sti_plane *plane,
plane->drm_plane.name,
plane->drm_plane.fb->width,
plane->drm_plane.fb->height,
- (char *)&plane->drm_plane.fb->pixel_format,
+ (char *)&plane->drm_plane.fb->format->format,
fpks / 1000, fpks % 1000,
sti_plane_to_str(plane));
}
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index ad46d3558d91..8b8ea717c121 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -567,13 +567,6 @@ static struct drm_info_list tvout_debugfs_files[] = {
{ "tvout", tvout_dbg_show, 0, NULL },
};
-static void tvout_debugfs_exit(struct sti_tvout *tvout, struct drm_minor *minor)
-{
- drm_debugfs_remove_files(tvout_debugfs_files,
- ARRAY_SIZE(tvout_debugfs_files),
- minor);
-}
-
static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor)
{
unsigned int i;
@@ -627,7 +620,6 @@ static void sti_tvout_early_unregister(struct drm_encoder *encoder)
if (!tvout->debugfs_registered)
return;
- tvout_debugfs_exit(tvout, encoder->dev->primary);
tvout->debugfs_registered = false;
}
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 0f4eacb0af4f..ef215fef63d6 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -804,23 +804,10 @@ static const struct file_operations tegra_drm_fops = {
.llseek = noop_llseek,
};
-static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
- unsigned int pipe)
-{
- struct drm_crtc *crtc;
-
- list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
- if (pipe == drm_crtc_index(crtc))
- return crtc;
- }
-
- return NULL;
-}
-
static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
unsigned int pipe)
{
- struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+ struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
struct tegra_dc *dc = to_tegra_dc(crtc);
if (!crtc)
@@ -831,7 +818,7 @@ static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
- struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+ struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
struct tegra_dc *dc = to_tegra_dc(crtc);
if (!crtc)
@@ -844,7 +831,7 @@ static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
static void tegra_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
{
- struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+ struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
struct tegra_dc *dc = to_tegra_dc(crtc);
if (crtc)
@@ -907,12 +894,6 @@ static int tegra_debugfs_init(struct drm_minor *minor)
ARRAY_SIZE(tegra_debugfs_list),
minor->debugfs_root, minor);
}
-
-static void tegra_debugfs_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(tegra_debugfs_list,
- ARRAY_SIZE(tegra_debugfs_list), minor);
-}
#endif
static struct drm_driver tegra_drm_driver = {
@@ -930,7 +911,6 @@ static struct drm_driver tegra_drm_driver = {
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = tegra_debugfs_init,
- .debugfs_cleanup = tegra_debugfs_cleanup,
#endif
.gem_free_object_unlocked = tegra_bo_free_object,
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 8df7783cecc2..f896e2ff7d47 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -271,8 +271,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
return 0;
destroy:
- drm_framebuffer_unregister_private(fb);
- tegra_fb_destroy(fb);
+ drm_framebuffer_remove(fb);
release:
drm_fb_helper_release_fbi(helper);
return err;
@@ -342,10 +341,8 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
drm_fb_helper_unregister_fbi(&fbdev->base);
drm_fb_helper_release_fbi(&fbdev->base);
- if (fbdev->fb) {
- drm_framebuffer_unregister_private(&fbdev->fb->base);
+ if (fbdev->fb)
drm_framebuffer_remove(&fbdev->fb->base);
- }
drm_fb_helper_fini(&fbdev->base);
tegra_fbdev_free(fbdev);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 3a763f7cb743..f80bf9385e41 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -856,7 +856,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct tilcdc_drm_private *priv = dev->dev_private;
- uint32_t stat;
+ uint32_t stat, reg;
stat = tilcdc_read_irqstatus(dev);
tilcdc_clear_irqstatus(dev, stat);
@@ -921,17 +921,26 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
__func__, stat);
tilcdc_crtc->frame_intact = false;
- if (tilcdc_crtc->sync_lost_count++ >
- SYNC_LOST_COUNT_LIMIT) {
- dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
- queue_work(system_wq, &tilcdc_crtc->recover_work);
- if (priv->rev == 1)
+ if (priv->rev == 1) {
+ reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG);
+ if (reg & LCDC_RASTER_ENABLE) {
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
- LCDC_V1_SYNC_LOST_INT_ENA);
- else
+ LCDC_RASTER_ENABLE);
+ tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
+ LCDC_RASTER_ENABLE);
+ }
+ } else {
+ if (tilcdc_crtc->sync_lost_count++ >
+ SYNC_LOST_COUNT_LIMIT) {
+ dev_err(dev->dev,
+ "%s(0x%08x): Sync lost flood detected, recovering",
+ __func__, stat);
+ queue_work(system_wq,
+ &tilcdc_crtc->recover_work);
tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
LCDC_SYNC_LOST);
- tilcdc_crtc->sync_lost_count = 0;
+ tilcdc_crtc->sync_lost_count = 0;
+ }
}
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index ec15585c7a27..919294a735fe 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -539,17 +539,6 @@ static int tilcdc_debugfs_init(struct drm_minor *minor)
return ret;
}
-
-static void tilcdc_debugfs_cleanup(struct drm_minor *minor)
-{
- struct tilcdc_module *mod;
- drm_debugfs_remove_files(tilcdc_debugfs_list,
- ARRAY_SIZE(tilcdc_debugfs_list), minor);
-
- list_for_each_entry(mod, &module_list, list)
- if (mod->funcs->debugfs_cleanup)
- mod->funcs->debugfs_cleanup(mod, minor);
-}
#endif
static const struct file_operations fops = {
@@ -589,7 +578,6 @@ static struct drm_driver tilcdc_driver = {
.gem_prime_mmap = drm_gem_cma_prime_mmap,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = tilcdc_debugfs_init,
- .debugfs_cleanup = tilcdc_debugfs_cleanup,
#endif
.fops = &fops,
.name = "tilcdc",
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 0e71daf5b5cb..8caa11bc7aec 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -111,8 +111,6 @@ struct tilcdc_module_ops {
#ifdef CONFIG_DEBUG_FS
/* create debugfs nodes (can be NULL): */
int (*debugfs_init)(struct tilcdc_module *mod, struct drm_minor *minor);
- /* cleanup debugfs nodes (can be NULL): */
- void (*debugfs_cleanup)(struct tilcdc_module *mod, struct drm_minor *minor);
#endif
};
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index d5063618efa7..4562e53c8244 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -163,6 +163,7 @@ static void ttm_bo_release_list(struct kref *list_kref)
void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
+ struct ttm_mem_type_manager *man;
lockdep_assert_held(&bo->resv->lock.base);
@@ -170,11 +171,13 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
BUG_ON(!list_empty(&bo->lru));
- list_add(&bo->lru, bdev->driver->lru_tail(bo));
+ man = &bdev->man[bo->mem.mem_type];
+ list_add_tail(&bo->lru, &man->lru[bo->priority]);
kref_get(&bo->list_kref);
if (bo->ttm && !(bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) {
- list_add(&bo->swap, bdev->driver->swap_lru_tail(bo));
+ list_add_tail(&bo->swap,
+ &bo->glob->swap_lru[bo->priority]);
kref_get(&bo->list_kref);
}
}
@@ -183,12 +186,8 @@ EXPORT_SYMBOL(ttm_bo_add_to_lru);
int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
{
- struct ttm_bo_device *bdev = bo->bdev;
int put_count = 0;
- if (bdev->driver->lru_removal)
- bdev->driver->lru_removal(bo);
-
if (!list_empty(&bo->swap)) {
list_del_init(&bo->swap);
++put_count;
@@ -198,6 +197,11 @@ int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
++put_count;
}
+ /*
+ * TODO: Add a driver hook to delete from
+ * driver-specific LRU's here.
+ */
+
return put_count;
}
@@ -226,32 +230,16 @@ EXPORT_SYMBOL(ttm_bo_del_sub_from_lru);
void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
{
- struct ttm_bo_device *bdev = bo->bdev;
int put_count = 0;
lockdep_assert_held(&bo->resv->lock.base);
- if (bdev->driver->lru_removal)
- bdev->driver->lru_removal(bo);
-
put_count = ttm_bo_del_from_lru(bo);
ttm_bo_list_ref_sub(bo, put_count, true);
ttm_bo_add_to_lru(bo);
}
EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
-struct list_head *ttm_bo_default_lru_tail(struct ttm_buffer_object *bo)
-{
- return bo->bdev->man[bo->mem.mem_type].lru.prev;
-}
-EXPORT_SYMBOL(ttm_bo_default_lru_tail);
-
-struct list_head *ttm_bo_default_swap_lru_tail(struct ttm_buffer_object *bo)
-{
- return bo->glob->swap_lru.prev;
-}
-EXPORT_SYMBOL(ttm_bo_default_swap_lru_tail);
-
/*
* Call bo->mutex locked.
*/
@@ -342,7 +330,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
if (bo->mem.mem_type == TTM_PL_SYSTEM) {
if (bdev->driver->move_notify)
- bdev->driver->move_notify(bo, mem);
+ bdev->driver->move_notify(bo, evict, mem);
bo->mem = *mem;
mem->mm_node = NULL;
goto moved;
@@ -350,7 +338,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
}
if (bdev->driver->move_notify)
- bdev->driver->move_notify(bo, mem);
+ bdev->driver->move_notify(bo, evict, mem);
if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
@@ -366,7 +354,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
struct ttm_mem_reg tmp_mem = *mem;
*mem = bo->mem;
bo->mem = tmp_mem;
- bdev->driver->move_notify(bo, mem);
+ bdev->driver->move_notify(bo, false, mem);
bo->mem = *mem;
*mem = tmp_mem;
}
@@ -414,7 +402,7 @@ out_err:
static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
{
if (bo->bdev->driver->move_notify)
- bo->bdev->driver->move_notify(bo, NULL);
+ bo->bdev->driver->move_notify(bo, false, NULL);
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
@@ -741,20 +729,27 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
struct ttm_mem_type_manager *man = &bdev->man[mem_type];
struct ttm_buffer_object *bo;
int ret = -EBUSY, put_count;
+ unsigned i;
spin_lock(&glob->lru_lock);
- list_for_each_entry(bo, &man->lru, lru) {
- ret = __ttm_bo_reserve(bo, false, true, NULL);
- if (ret)
- continue;
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+ list_for_each_entry(bo, &man->lru[i], lru) {
+ ret = __ttm_bo_reserve(bo, false, true, NULL);
+ if (ret)
+ continue;
- if (place && !bdev->driver->eviction_valuable(bo, place)) {
- __ttm_bo_unreserve(bo);
- ret = -EBUSY;
- continue;
+ if (place && !bdev->driver->eviction_valuable(bo,
+ place)) {
+ __ttm_bo_unreserve(bo);
+ ret = -EBUSY;
+ continue;
+ }
+
+ break;
}
- break;
+ if (!ret)
+ break;
}
if (ret) {
@@ -1197,6 +1192,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
}
atomic_inc(&bo->glob->bo_count);
drm_vma_node_reset(&bo->vma_node);
+ bo->priority = 0;
/*
* For ttm_bo_type_device buffers, allocate
@@ -1291,29 +1287,27 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
EXPORT_SYMBOL(ttm_bo_create);
static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
- unsigned mem_type, bool allow_errors)
+ unsigned mem_type)
{
struct ttm_mem_type_manager *man = &bdev->man[mem_type];
struct ttm_bo_global *glob = bdev->glob;
struct dma_fence *fence;
int ret;
+ unsigned i;
/*
* Can't use standard list traversal since we're unlocking.
*/
spin_lock(&glob->lru_lock);
- while (!list_empty(&man->lru)) {
- spin_unlock(&glob->lru_lock);
- ret = ttm_mem_evict_first(bdev, mem_type, NULL, false, false);
- if (ret) {
- if (allow_errors) {
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+ while (!list_empty(&man->lru[i])) {
+ spin_unlock(&glob->lru_lock);
+ ret = ttm_mem_evict_first(bdev, mem_type, NULL, false, false);
+ if (ret)
return ret;
- } else {
- pr_err("Cleanup eviction failed\n");
- }
+ spin_lock(&glob->lru_lock);
}
- spin_lock(&glob->lru_lock);
}
spin_unlock(&glob->lru_lock);
@@ -1324,13 +1318,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
if (fence) {
ret = dma_fence_wait(fence, false);
dma_fence_put(fence);
- if (ret) {
- if (allow_errors) {
- return ret;
- } else {
- pr_err("Cleanup eviction failed\n");
- }
- }
+ if (ret)
+ return ret;
}
return 0;
@@ -1359,7 +1348,11 @@ int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
ret = 0;
if (mem_type > 0) {
- ttm_bo_force_list_clean(bdev, mem_type, false);
+ ret = ttm_bo_force_list_clean(bdev, mem_type);
+ if (ret) {
+ pr_err("Cleanup eviction failed\n");
+ return ret;
+ }
ret = (*man->func->takedown)(man);
}
@@ -1382,7 +1375,7 @@ int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type)
return 0;
}
- return ttm_bo_force_list_clean(bdev, mem_type, true);
+ return ttm_bo_force_list_clean(bdev, mem_type);
}
EXPORT_SYMBOL(ttm_bo_evict_mm);
@@ -1391,6 +1384,7 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
{
int ret = -EINVAL;
struct ttm_mem_type_manager *man;
+ unsigned i;
BUG_ON(type >= TTM_NUM_MEM_TYPES);
man = &bdev->man[type];
@@ -1416,7 +1410,8 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
man->use_type = true;
man->size = p_size;
- INIT_LIST_HEAD(&man->lru);
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
+ INIT_LIST_HEAD(&man->lru[i]);
man->move = NULL;
return 0;
@@ -1448,6 +1443,7 @@ int ttm_bo_global_init(struct drm_global_reference *ref)
container_of(ref, struct ttm_bo_global_ref, ref);
struct ttm_bo_global *glob = ref->object;
int ret;
+ unsigned i;
mutex_init(&glob->device_list_mutex);
spin_lock_init(&glob->lru_lock);
@@ -1459,7 +1455,8 @@ int ttm_bo_global_init(struct drm_global_reference *ref)
goto out_no_drp;
}
- INIT_LIST_HEAD(&glob->swap_lru);
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
+ INIT_LIST_HEAD(&glob->swap_lru[i]);
INIT_LIST_HEAD(&glob->device_list);
ttm_mem_init_shrink(&glob->shrink, ttm_bo_swapout);
@@ -1518,8 +1515,9 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
if (list_empty(&bdev->ddestroy))
TTM_DEBUG("Delayed destroy list was clean\n");
- if (list_empty(&bdev->man[0].lru))
- TTM_DEBUG("Swap list was clean\n");
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
+ if (list_empty(&bdev->man[0].lru[0]))
+ TTM_DEBUG("Swap list %d was clean\n", i);
spin_unlock(&glob->lru_lock);
drm_vma_offset_manager_destroy(&bdev->vma_manager);
@@ -1670,11 +1668,15 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
struct ttm_buffer_object *bo;
int ret = -EBUSY;
int put_count;
- uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM);
+ unsigned i;
spin_lock(&glob->lru_lock);
- list_for_each_entry(bo, &glob->swap_lru, swap) {
- ret = __ttm_bo_reserve(bo, false, true, NULL);
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+ list_for_each_entry(bo, &glob->swap_lru[i], swap) {
+ ret = __ttm_bo_reserve(bo, false, true, NULL);
+ if (!ret)
+ break;
+ }
if (!ret)
break;
}
@@ -1701,7 +1703,8 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
* Move to system cached
*/
- if ((bo->mem.placement & swap_placement) != swap_placement) {
+ if (bo->mem.mem_type != TTM_PL_SYSTEM ||
+ bo->ttm->caching_state != tt_cached) {
struct ttm_mem_reg evict_mem;
evict_mem = bo->mem;
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index a0fd3e66bc4b..75b708b36890 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -156,7 +156,8 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
const struct drm_display_mode *mode)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
u32 val;
int fifo_lines;
int vblank_lines;
@@ -272,9 +273,7 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
int *max_error, struct timeval *vblank_time,
unsigned flags)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
- struct drm_crtc *crtc = &vc4_crtc->base;
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
struct drm_crtc_state *state = crtc->state;
/* Helper routine in DRM core does all the work: */
@@ -652,8 +651,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
CRTC_WRITE(PV_INTEN, PV_INT_VFP_START);
@@ -662,8 +661,8 @@ int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
CRTC_WRITE(PV_INTEN, 0);
}
@@ -937,7 +936,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = dev_get_drvdata(master);
- struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_crtc *vc4_crtc;
struct drm_crtc *crtc;
struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
@@ -975,7 +973,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
&vc4_crtc_funcs, NULL);
drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
primary_plane->crtc = crtc;
- vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
vc4_crtc->channel = vc4_crtc->data->hvs_channel;
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index caf817bac885..c4d5e6a8d6f2 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -36,9 +36,3 @@ vc4_debugfs_init(struct drm_minor *minor)
return drm_debugfs_create_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
}
-
-void
-vc4_debugfs_cleanup(struct drm_minor *minor)
-{
- drm_debugfs_remove_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor);
-}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index ac09ca7ff430..e4f42ebee517 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -145,7 +145,6 @@ static struct drm_driver vc4_drm_driver = {
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = vc4_debugfs_init,
- .debugfs_cleanup = vc4_debugfs_cleanup,
#endif
.gem_create_object = vc4_create_object,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 489956efbff8..78e3e5a43fb0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -16,7 +16,6 @@ struct vc4_dev {
struct vc4_hdmi *hdmi;
struct vc4_hvs *hvs;
- struct vc4_crtc *crtc[3];
struct vc4_v3d *v3d;
struct vc4_dpi *dpi;
struct vc4_vec *vec;
@@ -458,7 +457,6 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
/* vc4_debugfs.c */
int vc4_debugfs_init(struct drm_minor *minor);
-void vc4_debugfs_cleanup(struct drm_minor *minor);
/* vc4_drv.c */
void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index c4cb2e26de32..93d5994f3a04 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -356,15 +356,11 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
return;
}
- if (vc4_encoder->rgb_range_selectable) {
- if (vc4_encoder->limited_rgb_range) {
- frame.avi.quantization_range =
- HDMI_QUANTIZATION_RANGE_LIMITED;
- } else {
- frame.avi.quantization_range =
- HDMI_QUANTIZATION_RANGE_FULL;
- }
- }
+ drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode,
+ vc4_encoder->limited_rgb_range ?
+ HDMI_QUANTIZATION_RANGE_LIMITED :
+ HDMI_QUANTIZATION_RANGE_FULL,
+ vc4_encoder->rgb_range_selectable);
vc4_hdmi_write_infoframe(encoder, &frame);
}
@@ -463,7 +459,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
VC4_HD_CSC_CTL_ORDER);
- if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
+ if (vc4_encoder->hdmi_monitor &&
+ drm_default_rgb_quant_range(mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED) {
/* CEA VICs other than #1 requre limited range RGB
* output unless overridden by an AVI infoframe.
* Apply a colorspace conversion to squash 0-255 down
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h
index 1f8798ad329c..cb59c7ab98b9 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.h
+++ b/drivers/gpu/drm/vgem/vgem_drv.h
@@ -31,6 +31,7 @@
#include <drm/drmP.h>
#include <drm/drm_gem.h>
+#include <drm/drm_cache.h>
#include <uapi/drm/vgem_drm.h>
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index da25dfe7b80e..3109c8308eb5 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -190,12 +190,12 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
/* Expose the fence via the dma-buf */
ret = 0;
- ww_mutex_lock(&resv->lock, NULL);
+ reservation_object_lock(resv, NULL);
if (arg->flags & VGEM_FENCE_WRITE)
reservation_object_add_excl_fence(resv, fence);
else if ((ret = reservation_object_reserve_shared(resv)) == 0)
reservation_object_add_shared_fence(resv, fence);
- ww_mutex_unlock(&resv->lock);
+ reservation_object_unlock(resv);
/* Record the fence in our idr for later signaling */
if (ret == 0) {
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index 61254b991265..24f99fc9d8a4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -331,7 +331,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
info->fbops = &virtio_gpufb_ops;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->screen_base = obj->vmap;
+ info->screen_buffer = obj->vmap;
info->screen_size = obj->gem_base.size;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
drm_fb_helper_fill_var(info, &vfbdev->helper,
diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c
index 63b3d5d35cf6..9cc7079f7aca 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ttm.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c
@@ -386,6 +386,7 @@ static int virtio_gpu_bo_move(struct ttm_buffer_object *bo,
}
static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo,
+ bool evict,
struct ttm_mem_reg *new_mem)
{
struct virtio_gpu_object *bo;
@@ -433,8 +434,6 @@ static struct ttm_bo_driver virtio_gpu_bo_driver = {
.io_mem_free = &virtio_gpu_ttm_io_mem_free,
.move_notify = &virtio_gpu_bo_move_notify,
.swap_notify = &virtio_gpu_bo_swap_notify,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
index c7cf48c0ad3e..4c7f24a67a2e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
@@ -825,6 +825,7 @@ static int vmw_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
* (currently only resources).
*/
static void vmw_move_notify(struct ttm_buffer_object *bo,
+ bool evict,
struct ttm_mem_reg *mem)
{
vmw_resource_move_notify(bo, mem);
@@ -858,6 +859,4 @@ struct ttm_bo_driver vmw_bo_driver = {
.fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
.io_mem_reserve = &vmw_ttm_io_mem_reserve,
.io_mem_free = &vmw_ttm_io_mem_free,
- .lru_tail = &ttm_bo_default_lru_tail,
- .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
};
diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
index 4065b2840f1c..5b36421ef3e5 100644
--- a/drivers/gpu/drm/zte/Kconfig
+++ b/drivers/gpu/drm/zte/Kconfig
@@ -4,5 +4,7 @@ config DRM_ZTE
select DRM_KMS_CMA_HELPER
select DRM_KMS_FB_HELPER
select DRM_KMS_HELPER
+ select SND_SOC_HDMI_CODEC if SND_SOC
+ select VIDEOMODE_HELPERS
help
Choose this option to enable DRM on ZTE ZX SoCs.
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
index 699180bfd57c..01352b56c418 100644
--- a/drivers/gpu/drm/zte/Makefile
+++ b/drivers/gpu/drm/zte/Makefile
@@ -2,6 +2,7 @@ zxdrm-y := \
zx_drm_drv.o \
zx_hdmi.o \
zx_plane.o \
+ zx_tvenc.o \
zx_vou.o
obj-$(CONFIG_DRM_ZTE) += zxdrm.o
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 3e76f72c92ff..13081fed902d 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -247,6 +247,7 @@ static struct platform_driver zx_drm_platform_driver = {
static struct platform_driver *drivers[] = {
&zx_crtc_driver,
&zx_hdmi_driver,
+ &zx_tvenc_driver,
&zx_drm_platform_driver,
};
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
index e65cd18a6cba..5ca035b079c7 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.h
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -13,6 +13,7 @@
extern struct platform_driver zx_crtc_driver;
extern struct platform_driver zx_hdmi_driver;
+extern struct platform_driver zx_tvenc_driver;
static inline u32 zx_readl(void __iomem *reg)
{
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
index 6bf6c364811e..c47b9cbfe270 100644
--- a/drivers/gpu/drm/zte/zx_hdmi.c
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -25,6 +25,8 @@
#include <drm/drm_of.h>
#include <drm/drmP.h>
+#include <sound/hdmi-codec.h>
+
#include "zx_hdmi_regs.h"
#include "zx_vou.h"
@@ -49,17 +51,11 @@ struct zx_hdmi {
bool sink_is_hdmi;
bool sink_has_audio;
const struct vou_inf *inf;
+ struct platform_device *audio_pdev;
};
#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
-static const struct vou_inf vou_inf_hdmi = {
- .id = VOU_HDMI,
- .data_sel = VOU_YUV444,
- .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
- .clocks_sel_bits = BIT(13) | BIT(2),
-};
-
static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
{
return readl_relaxed(hdmi->mmio + offset * 4);
@@ -238,14 +234,14 @@ static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
zx_hdmi_hw_enable(hdmi);
- vou_inf_enable(hdmi->inf, encoder->crtc);
+ vou_inf_enable(VOU_HDMI, encoder->crtc);
}
static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
{
struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
- vou_inf_disable(hdmi->inf, encoder->crtc);
+ vou_inf_disable(VOU_HDMI, encoder->crtc);
zx_hdmi_hw_disable(hdmi);
@@ -366,6 +362,142 @@ static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static int zx_hdmi_audio_startup(struct device *dev, void *data)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct drm_encoder *encoder = &hdmi->encoder;
+
+ vou_inf_hdmi_audio_sel(encoder->crtc, VOU_HDMI_AUD_SPDIF);
+
+ return 0;
+}
+
+static void zx_hdmi_audio_shutdown(struct device *dev, void *data)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+
+ /* Disable audio input */
+ hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, 0);
+}
+
+static inline int zx_hdmi_audio_get_n(unsigned int fs)
+{
+ unsigned int n;
+
+ if (fs && (fs % 44100) == 0)
+ n = 6272 * (fs / 44100);
+ else
+ n = fs * 128 / 1000;
+
+ return n;
+}
+
+static int zx_hdmi_audio_hw_params(struct device *dev,
+ void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct hdmi_audio_infoframe *cea = &params->cea;
+ union hdmi_infoframe frame;
+ int n;
+
+ /* We only support spdif for now */
+ if (daifmt->fmt != HDMI_SPDIF) {
+ DRM_DEV_ERROR(hdmi->dev, "invalid daifmt %d\n", daifmt->fmt);
+ return -EINVAL;
+ }
+
+ switch (params->sample_width) {
+ case 16:
+ hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
+ SPDIF_SAMPLE_SIZE_16BIT);
+ break;
+ case 20:
+ hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
+ SPDIF_SAMPLE_SIZE_20BIT);
+ break;
+ case 24:
+ hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
+ SPDIF_SAMPLE_SIZE_24BIT);
+ break;
+ default:
+ DRM_DEV_ERROR(hdmi->dev, "invalid sample width %d\n",
+ params->sample_width);
+ return -EINVAL;
+ }
+
+ /* CTS is calculated by hardware, and we only need to take care of N */
+ n = zx_hdmi_audio_get_n(params->sample_rate);
+ hdmi_writeb(hdmi, N_SVAL1, n & 0xff);
+ hdmi_writeb(hdmi, N_SVAL2, (n >> 8) & 0xff);
+ hdmi_writeb(hdmi, N_SVAL3, (n >> 16) & 0xf);
+
+ /* Enable spdif mode */
+ hdmi_writeb_mask(hdmi, AUD_MODE, SPDIF_EN, SPDIF_EN);
+
+ /* Enable audio input */
+ hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, AUD_IN_EN);
+
+ memcpy(&frame.audio, cea, sizeof(*cea));
+
+ return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AUDIO);
+}
+
+static int zx_hdmi_audio_digital_mute(struct device *dev, void *data,
+ bool enable)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (enable)
+ hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE,
+ TPI_AUD_MUTE);
+ else
+ hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE, 0);
+
+ return 0;
+}
+
+static int zx_hdmi_audio_get_eld(struct device *dev, void *data,
+ uint8_t *buf, size_t len)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct drm_connector *connector = &hdmi->connector;
+
+ memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
+
+ return 0;
+}
+
+static const struct hdmi_codec_ops zx_hdmi_codec_ops = {
+ .audio_startup = zx_hdmi_audio_startup,
+ .hw_params = zx_hdmi_audio_hw_params,
+ .audio_shutdown = zx_hdmi_audio_shutdown,
+ .digital_mute = zx_hdmi_audio_digital_mute,
+ .get_eld = zx_hdmi_audio_get_eld,
+};
+
+static struct hdmi_codec_pdata zx_hdmi_codec_pdata = {
+ .ops = &zx_hdmi_codec_ops,
+ .spdif = 1,
+};
+
+static int zx_hdmi_audio_register(struct zx_hdmi *hdmi)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(hdmi->dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &zx_hdmi_codec_pdata,
+ sizeof(zx_hdmi_codec_pdata));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ hdmi->audio_pdev = pdev;
+
+ return 0;
+}
+
static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg)
{
int len = msg->len;
@@ -523,7 +655,6 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi->dev = dev;
hdmi->drm = drm;
- hdmi->inf = &vou_inf_hdmi;
dev_set_drvdata(dev, hdmi);
@@ -566,6 +697,12 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
}
+ ret = zx_hdmi_audio_register(hdmi);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register audio: %d\n", ret);
+ return ret;
+ }
+
ret = zx_hdmi_register(drm, hdmi);
if (ret) {
DRM_DEV_ERROR(dev, "failed to register hdmi: %d\n", ret);
@@ -590,6 +727,9 @@ static void zx_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
+
+ if (hdmi->audio_pdev)
+ platform_device_unregister(hdmi->audio_pdev);
}
static const struct component_ops zx_hdmi_component_ops = {
diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h
index de911f66b658..c6d5d8211725 100644
--- a/drivers/gpu/drm/zte/zx_hdmi_regs.h
+++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h
@@ -52,5 +52,19 @@
#define TPI_INFO_TRANS_RPT BIT(6)
#define TPI_DDC_MASTER_EN 0x06f8
#define HW_DDC_MASTER BIT(7)
+#define N_SVAL1 0xa03
+#define N_SVAL2 0xa04
+#define N_SVAL3 0xa05
+#define AUD_EN 0xa13
+#define AUD_IN_EN BIT(0)
+#define AUD_MODE 0xa14
+#define SPDIF_EN BIT(1)
+#define TPI_AUD_CONFIG 0xa62
+#define SPDIF_SAMPLE_SIZE_SHIFT 6
+#define SPDIF_SAMPLE_SIZE_MASK (0x3 << SPDIF_SAMPLE_SIZE_SHIFT)
+#define SPDIF_SAMPLE_SIZE_16BIT (0x1 << SPDIF_SAMPLE_SIZE_SHIFT)
+#define SPDIF_SAMPLE_SIZE_20BIT (0x2 << SPDIF_SAMPLE_SIZE_SHIFT)
+#define SPDIF_SAMPLE_SIZE_24BIT (0x3 << SPDIF_SAMPLE_SIZE_SHIFT)
+#define TPI_AUD_MUTE BIT(4)
#endif /* __ZX_HDMI_REGS_H__ */
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index b634b090cdc1..1d08ba381098 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -21,16 +21,6 @@
#include "zx_plane_regs.h"
#include "zx_vou.h"
-struct zx_plane {
- struct drm_plane plane;
- void __iomem *layer;
- void __iomem *csc;
- void __iomem *hbsc;
- void __iomem *rsz;
-};
-
-#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
-
static const uint32_t gl_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
@@ -40,6 +30,261 @@ static const uint32_t gl_formats[] = {
DRM_FORMAT_ARGB4444,
};
+static const uint32_t vl_formats[] = {
+ DRM_FORMAT_NV12, /* Semi-planar YUV420 */
+ DRM_FORMAT_YUV420, /* Planar YUV420 */
+ DRM_FORMAT_YUYV, /* Packed YUV422 */
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YUV444, /* YUV444 8bit */
+ /*
+ * TODO: add formats below that HW supports:
+ * - YUV420 P010
+ * - YUV420 Hantro
+ * - YUV444 10bit
+ */
+};
+
+#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
+
+static int zx_vl_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_crtc *crtc = plane_state->crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_rect clip;
+ int min_scale = FRAC_16_16(1, 8);
+ int max_scale = FRAC_16_16(8, 1);
+
+ if (!crtc || !fb)
+ return 0;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
+ crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+
+ /* nothing to check when disabling or disabled */
+ if (!crtc_state->enable)
+ return 0;
+
+ /* plane must be enabled */
+ if (!plane_state->crtc)
+ return -EINVAL;
+
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+
+ return drm_plane_helper_check_state(plane_state, &clip,
+ min_scale, max_scale,
+ true, true);
+}
+
+static int zx_vl_get_fmt(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ return VL_FMT_YUV420;
+ case DRM_FORMAT_YUV420:
+ return VL_YUV420_PLANAR | VL_FMT_YUV420;
+ case DRM_FORMAT_YUYV:
+ return VL_YUV422_YUYV | VL_FMT_YUV422;
+ case DRM_FORMAT_YVYU:
+ return VL_YUV422_YVYU | VL_FMT_YUV422;
+ case DRM_FORMAT_UYVY:
+ return VL_YUV422_UYVY | VL_FMT_YUV422;
+ case DRM_FORMAT_VYUY:
+ return VL_YUV422_VYUY | VL_FMT_YUV422;
+ case DRM_FORMAT_YUV444:
+ return VL_FMT_YUV444_8BIT;
+ default:
+ WARN_ONCE(1, "invalid pixel format %d\n", format);
+ return -EINVAL;
+ }
+}
+
+static inline void zx_vl_set_update(struct zx_plane *zplane)
+{
+ void __iomem *layer = zplane->layer;
+
+ zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
+}
+
+static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
+{
+ zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
+}
+
+static int zx_vl_rsz_get_fmt(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_YUV420:
+ return RSZ_VL_FMT_YCBCR420;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ return RSZ_VL_FMT_YCBCR422;
+ case DRM_FORMAT_YUV444:
+ return RSZ_VL_FMT_YCBCR444;
+ default:
+ WARN_ONCE(1, "invalid pixel format %d\n", format);
+ return -EINVAL;
+ }
+}
+
+static inline u32 rsz_step_value(u32 src, u32 dst)
+{
+ u32 val = 0;
+
+ if (src == dst)
+ val = 0;
+ else if (src < dst)
+ val = RSZ_PARA_STEP((src << 16) / dst);
+ else if (src > dst)
+ val = RSZ_DATA_STEP(src / dst) |
+ RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
+
+ return val;
+}
+
+static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
+ u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
+{
+ void __iomem *rsz = zplane->rsz;
+ u32 src_chroma_w = src_w;
+ u32 src_chroma_h = src_h;
+ u32 fmt;
+
+ /* Set up source and destination resolution */
+ zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
+ zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
+
+ /* Configure data format for VL RSZ */
+ fmt = zx_vl_rsz_get_fmt(format);
+ if (fmt >= 0)
+ zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
+
+ /* Calculate Chroma height and width */
+ if (fmt == RSZ_VL_FMT_YCBCR420) {
+ src_chroma_w = src_w >> 1;
+ src_chroma_h = src_h >> 1;
+ } else if (fmt == RSZ_VL_FMT_YCBCR422) {
+ src_chroma_w = src_w >> 1;
+ }
+
+ /* Set up Luma and Chroma step registers */
+ zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
+ zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
+ zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
+ zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
+
+ zx_vl_rsz_set_update(zplane);
+}
+
+static void zx_vl_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct zx_plane *zplane = to_zx_plane(plane);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_rect *src = &state->src;
+ struct drm_rect *dst = &state->dst;
+ struct drm_gem_cma_object *cma_obj;
+ void __iomem *layer = zplane->layer;
+ void __iomem *hbsc = zplane->hbsc;
+ void __iomem *paddr_reg;
+ dma_addr_t paddr;
+ u32 src_x, src_y, src_w, src_h;
+ u32 dst_x, dst_y, dst_w, dst_h;
+ uint32_t format;
+ u32 fmt;
+ int num_planes;
+ int i;
+
+ if (!fb)
+ return;
+
+ format = fb->format->format;
+
+ src_x = src->x1 >> 16;
+ src_y = src->y1 >> 16;
+ src_w = drm_rect_width(src) >> 16;
+ src_h = drm_rect_height(src) >> 16;
+
+ dst_x = dst->x1;
+ dst_y = dst->y1;
+ dst_w = drm_rect_width(dst);
+ dst_h = drm_rect_height(dst);
+
+ /* Set up data address registers for Y, Cb and Cr planes */
+ num_planes = drm_format_num_planes(format);
+ paddr_reg = layer + VL_Y;
+ for (i = 0; i < num_planes; i++) {
+ cma_obj = drm_fb_cma_get_gem_obj(fb, i);
+ paddr = cma_obj->paddr + fb->offsets[i];
+ paddr += src_y * fb->pitches[i];
+ paddr += src_x * drm_format_plane_cpp(format, i);
+ zx_writel(paddr_reg, paddr);
+ paddr_reg += 4;
+ }
+
+ /* Set up source height/width register */
+ zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
+
+ /* Set up start position register */
+ zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
+
+ /* Set up end position register */
+ zx_writel(layer + VL_POS_END,
+ GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
+
+ /* Strides of Cb and Cr planes should be identical */
+ zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
+ CHROMA_STRIDE(fb->pitches[1]));
+
+ /* Set up video layer data format */
+ fmt = zx_vl_get_fmt(format);
+ if (fmt >= 0)
+ zx_writel(layer + VL_CTRL1, fmt);
+
+ /* Always use scaler since it exists (set for not bypass) */
+ zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
+ VL_SCALER_BYPASS_MODE);
+
+ zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
+
+ /* Enable HBSC block */
+ zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
+
+ zx_vou_layer_enable(plane);
+
+ zx_vl_set_update(zplane);
+}
+
+static void zx_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct zx_plane *zplane = to_zx_plane(plane);
+ void __iomem *hbsc = zplane->hbsc;
+
+ zx_vou_layer_disable(plane);
+
+ /* Disable HBSC block */
+ zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
+}
+
+static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
+ .atomic_check = zx_vl_plane_atomic_check,
+ .atomic_update = zx_vl_plane_atomic_update,
+ .atomic_disable = zx_plane_atomic_disable,
+};
+
static int zx_gl_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *plane_state)
{
@@ -107,14 +352,6 @@ static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
}
-void zx_plane_set_update(struct drm_plane *plane)
-{
- struct zx_plane *zplane = to_zx_plane(plane);
-
- zx_gl_rsz_set_update(zplane);
- zx_gl_set_update(zplane);
-}
-
static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
u32 dst_w, u32 dst_h)
{
@@ -207,12 +444,15 @@ static void zx_gl_plane_atomic_update(struct drm_plane *plane,
/* Enable HBSC block */
zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
+ zx_vou_layer_enable(plane);
+
zx_gl_set_update(zplane);
}
static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
.atomic_check = zx_gl_plane_atomic_check,
.atomic_update = zx_gl_plane_atomic_update,
+ .atomic_disable = zx_plane_atomic_disable,
};
static void zx_plane_destroy(struct drm_plane *plane)
@@ -230,6 +470,28 @@ static const struct drm_plane_funcs zx_plane_funcs = {
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
+void zx_plane_set_update(struct drm_plane *plane)
+{
+ struct zx_plane *zplane = to_zx_plane(plane);
+
+ /* Do nothing if the plane is not enabled */
+ if (!plane->state->crtc)
+ return;
+
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ zx_gl_rsz_set_update(zplane);
+ zx_gl_set_update(zplane);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ zx_vl_rsz_set_update(zplane);
+ zx_vl_set_update(zplane);
+ break;
+ default:
+ WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
+ }
+}
+
static void zx_plane_hbsc_init(struct zx_plane *zplane)
{
void __iomem *hbsc = zplane->hbsc;
@@ -248,28 +510,16 @@ static void zx_plane_hbsc_init(struct zx_plane *zplane)
zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
}
-struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
- struct zx_layer_data *data,
- enum drm_plane_type type)
+int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
+ enum drm_plane_type type)
{
const struct drm_plane_helper_funcs *helper;
- struct zx_plane *zplane;
- struct drm_plane *plane;
+ struct drm_plane *plane = &zplane->plane;
+ struct device *dev = zplane->dev;
const uint32_t *formats;
unsigned int format_count;
int ret;
- zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
- if (!zplane)
- return ERR_PTR(-ENOMEM);
-
- plane = &zplane->plane;
-
- zplane->layer = data->layer;
- zplane->hbsc = data->hbsc;
- zplane->csc = data->csc;
- zplane->rsz = data->rsz;
-
zx_plane_hbsc_init(zplane);
switch (type) {
@@ -279,10 +529,12 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
format_count = ARRAY_SIZE(gl_formats);
break;
case DRM_PLANE_TYPE_OVERLAY:
- /* TODO: add video layer (vl) support */
+ helper = &zx_vl_plane_helper_funcs;
+ formats = vl_formats;
+ format_count = ARRAY_SIZE(vl_formats);
break;
default:
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
@@ -290,10 +542,10 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
type, NULL);
if (ret) {
DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
- return ERR_PTR(ret);
+ return ret;
}
drm_plane_helper_add(plane, helper);
- return plane;
+ return 0;
}
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
index 2b82cd558d9d..933611ddffd0 100644
--- a/drivers/gpu/drm/zte/zx_plane.h
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -11,16 +11,20 @@
#ifndef __ZX_PLANE_H__
#define __ZX_PLANE_H__
-struct zx_layer_data {
+struct zx_plane {
+ struct drm_plane plane;
+ struct device *dev;
void __iomem *layer;
void __iomem *csc;
void __iomem *hbsc;
void __iomem *rsz;
+ const struct vou_layer_bits *bits;
};
-struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
- struct zx_layer_data *data,
- enum drm_plane_type type);
+#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
+
+int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
+ enum drm_plane_type type);
void zx_plane_set_update(struct drm_plane *plane);
#endif /* __ZX_PLANE_H__ */
diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
index 3dde6716a558..65f271aeabed 100644
--- a/drivers/gpu/drm/zte/zx_plane_regs.h
+++ b/drivers/gpu/drm/zte/zx_plane_regs.h
@@ -46,6 +46,37 @@
#define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
#define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
+/* VL registers */
+#define VL_CTRL0 0x00
+#define VL_UPDATE BIT(3)
+#define VL_CTRL1 0x04
+#define VL_YUV420_PLANAR BIT(5)
+#define VL_YUV422_SHIFT 3
+#define VL_YUV422_YUYV (0 << VL_YUV422_SHIFT)
+#define VL_YUV422_YVYU (1 << VL_YUV422_SHIFT)
+#define VL_YUV422_UYVY (2 << VL_YUV422_SHIFT)
+#define VL_YUV422_VYUY (3 << VL_YUV422_SHIFT)
+#define VL_FMT_YUV420 0
+#define VL_FMT_YUV422 1
+#define VL_FMT_YUV420_P010 2
+#define VL_FMT_YUV420_HANTRO 3
+#define VL_FMT_YUV444_8BIT 4
+#define VL_FMT_YUV444_10BIT 5
+#define VL_CTRL2 0x08
+#define VL_SCALER_BYPASS_MODE BIT(0)
+#define VL_STRIDE 0x0c
+#define LUMA_STRIDE_SHIFT 16
+#define LUMA_STRIDE_MASK (0xffff << LUMA_STRIDE_SHIFT)
+#define CHROMA_STRIDE_SHIFT 0
+#define CHROMA_STRIDE_MASK (0xffff << CHROMA_STRIDE_SHIFT)
+#define VL_SRC_SIZE 0x10
+#define VL_Y 0x14
+#define VL_POS_START 0x30
+#define VL_POS_END 0x34
+
+#define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK)
+#define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK)
+
/* CSC registers */
#define CSC_CTRL0 0x30
#define CSC_COV_MODE_SHIFT 16
@@ -69,6 +100,18 @@
#define RSZ_DEST_CFG 0x04
#define RSZ_ENABLE_CFG 0x14
+#define RSZ_VL_LUMA_HOR 0x08
+#define RSZ_VL_LUMA_VER 0x0c
+#define RSZ_VL_CHROMA_HOR 0x10
+#define RSZ_VL_CHROMA_VER 0x14
+#define RSZ_VL_CTRL_CFG 0x18
+#define RSZ_VL_FMT_SHIFT 3
+#define RSZ_VL_FMT_MASK (0x3 << RSZ_VL_FMT_SHIFT)
+#define RSZ_VL_FMT_YCBCR420 (0x0 << RSZ_VL_FMT_SHIFT)
+#define RSZ_VL_FMT_YCBCR422 (0x1 << RSZ_VL_FMT_SHIFT)
+#define RSZ_VL_FMT_YCBCR444 (0x2 << RSZ_VL_FMT_SHIFT)
+#define RSZ_VL_ENABLE_CFG 0x1c
+
#define RSZ_VER_SHIFT 16
#define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT)
#define RSZ_HOR_SHIFT 0
@@ -77,6 +120,14 @@
#define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
#define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
+#define RSZ_DATA_STEP_SHIFT 16
+#define RSZ_DATA_STEP_MASK (0xffff << RSZ_DATA_STEP_SHIFT)
+#define RSZ_PARA_STEP_SHIFT 0
+#define RSZ_PARA_STEP_MASK (0xffff << RSZ_PARA_STEP_SHIFT)
+
+#define RSZ_DATA_STEP(x) (((x) << RSZ_DATA_STEP_SHIFT) & RSZ_DATA_STEP_MASK)
+#define RSZ_PARA_STEP(x) (((x) << RSZ_PARA_STEP_SHIFT) & RSZ_PARA_STEP_MASK)
+
/* HBSC registers */
#define HBSC_SATURATION 0x00
#define HBSC_HUE 0x04
diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
new file mode 100644
index 000000000000..b56dc69843fc
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2017 Linaro Ltd.
+ * Copyright 2017 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include "zx_drm_drv.h"
+#include "zx_tvenc_regs.h"
+#include "zx_vou.h"
+
+struct zx_tvenc_pwrctrl {
+ struct regmap *regmap;
+ u32 reg;
+ u32 mask;
+};
+
+struct zx_tvenc {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct device *dev;
+ void __iomem *mmio;
+ const struct vou_inf *inf;
+ struct zx_tvenc_pwrctrl pwrctrl;
+};
+
+#define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
+
+struct zx_tvenc_mode {
+ struct drm_display_mode mode;
+ u32 video_info;
+ u32 video_res;
+ u32 field1_param;
+ u32 field2_param;
+ u32 burst_line_odd1;
+ u32 burst_line_even1;
+ u32 burst_line_odd2;
+ u32 burst_line_even2;
+ u32 line_timing_param;
+ u32 weight_value;
+ u32 blank_black_level;
+ u32 burst_level;
+ u32 control_param;
+ u32 sub_carrier_phase1;
+ u32 phase_line_incr_cvbs;
+};
+
+/*
+ * The CRM cannot directly provide a suitable frequency, and we have to
+ * ask a multiplied rate from CRM and use the divider in VOU to get the
+ * desired one.
+ */
+#define TVENC_CLOCK_MULTIPLIER 4
+
+static const struct zx_tvenc_mode tvenc_mode_pal = {
+ .mode = {
+ .clock = 13500 * TVENC_CLOCK_MULTIPLIER,
+ .hdisplay = 720,
+ .hsync_start = 720 + 12,
+ .hsync_end = 720 + 12 + 2,
+ .htotal = 720 + 12 + 2 + 130,
+ .vdisplay = 576,
+ .vsync_start = 576 + 2,
+ .vsync_end = 576 + 2 + 2,
+ .vtotal = 576 + 2 + 2 + 20,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_INTERLACE,
+ },
+ .video_info = 0x00040040,
+ .video_res = 0x05a9c760,
+ .field1_param = 0x0004d416,
+ .field2_param = 0x0009b94f,
+ .burst_line_odd1 = 0x0004d406,
+ .burst_line_even1 = 0x0009b53e,
+ .burst_line_odd2 = 0x0004d805,
+ .burst_line_even2 = 0x0009b93f,
+ .line_timing_param = 0x06a96fdf,
+ .weight_value = 0x00c188a0,
+ .blank_black_level = 0x0000fcfc,
+ .burst_level = 0x00001595,
+ .control_param = 0x00000001,
+ .sub_carrier_phase1 = 0x1504c566,
+ .phase_line_incr_cvbs = 0xc068db8c,
+};
+
+static const struct zx_tvenc_mode tvenc_mode_ntsc = {
+ .mode = {
+ .clock = 13500 * TVENC_CLOCK_MULTIPLIER,
+ .hdisplay = 720,
+ .hsync_start = 720 + 16,
+ .hsync_end = 720 + 16 + 2,
+ .htotal = 720 + 16 + 2 + 120,
+ .vdisplay = 480,
+ .vsync_start = 480 + 3,
+ .vsync_end = 480 + 3 + 2,
+ .vtotal = 480 + 3 + 2 + 17,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_INTERLACE,
+ },
+ .video_info = 0x00040080,
+ .video_res = 0x05a8375a,
+ .field1_param = 0x00041817,
+ .field2_param = 0x0008351e,
+ .burst_line_odd1 = 0x00041006,
+ .burst_line_even1 = 0x0008290d,
+ .burst_line_odd2 = 0x00000000,
+ .burst_line_even2 = 0x00000000,
+ .line_timing_param = 0x06a8ef9e,
+ .weight_value = 0x00b68197,
+ .blank_black_level = 0x0000f0f0,
+ .burst_level = 0x0000009c,
+ .control_param = 0x00000001,
+ .sub_carrier_phase1 = 0x10f83e10,
+ .phase_line_incr_cvbs = 0x80000000,
+};
+
+static const struct zx_tvenc_mode *tvenc_modes[] = {
+ &tvenc_mode_pal,
+ &tvenc_mode_ntsc,
+};
+
+static const struct zx_tvenc_mode *
+zx_tvenc_find_zmode(struct drm_display_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
+ const struct zx_tvenc_mode *zmode = tvenc_modes[i];
+
+ if (drm_mode_equal(mode, &zmode->mode))
+ return zmode;
+ }
+
+ return NULL;
+}
+
+static void zx_tvenc_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+ const struct zx_tvenc_mode *zmode;
+ struct vou_div_config configs[] = {
+ { VOU_DIV_INF, VOU_DIV_4 },
+ { VOU_DIV_TVENC, VOU_DIV_1 },
+ { VOU_DIV_LAYER, VOU_DIV_2 },
+ };
+
+ zx_vou_config_dividers(encoder->crtc, configs, ARRAY_SIZE(configs));
+
+ zmode = zx_tvenc_find_zmode(mode);
+ if (!zmode) {
+ DRM_DEV_ERROR(tvenc->dev, "failed to find zmode\n");
+ return;
+ }
+
+ zx_writel(tvenc->mmio + VENC_VIDEO_INFO, zmode->video_info);
+ zx_writel(tvenc->mmio + VENC_VIDEO_RES, zmode->video_res);
+ zx_writel(tvenc->mmio + VENC_FIELD1_PARAM, zmode->field1_param);
+ zx_writel(tvenc->mmio + VENC_FIELD2_PARAM, zmode->field2_param);
+ zx_writel(tvenc->mmio + VENC_LINE_O_1, zmode->burst_line_odd1);
+ zx_writel(tvenc->mmio + VENC_LINE_E_1, zmode->burst_line_even1);
+ zx_writel(tvenc->mmio + VENC_LINE_O_2, zmode->burst_line_odd2);
+ zx_writel(tvenc->mmio + VENC_LINE_E_2, zmode->burst_line_even2);
+ zx_writel(tvenc->mmio + VENC_LINE_TIMING_PARAM,
+ zmode->line_timing_param);
+ zx_writel(tvenc->mmio + VENC_WEIGHT_VALUE, zmode->weight_value);
+ zx_writel(tvenc->mmio + VENC_BLANK_BLACK_LEVEL,
+ zmode->blank_black_level);
+ zx_writel(tvenc->mmio + VENC_BURST_LEVEL, zmode->burst_level);
+ zx_writel(tvenc->mmio + VENC_CONTROL_PARAM, zmode->control_param);
+ zx_writel(tvenc->mmio + VENC_SUB_CARRIER_PHASE1,
+ zmode->sub_carrier_phase1);
+ zx_writel(tvenc->mmio + VENC_PHASE_LINE_INCR_CVBS,
+ zmode->phase_line_incr_cvbs);
+}
+
+static void zx_tvenc_encoder_enable(struct drm_encoder *encoder)
+{
+ struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+ struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+
+ /* Set bit to power up TVENC DAC */
+ regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask,
+ pwrctrl->mask);
+
+ vou_inf_enable(VOU_TV_ENC, encoder->crtc);
+
+ zx_writel(tvenc->mmio + VENC_ENABLE, 1);
+}
+
+static void zx_tvenc_encoder_disable(struct drm_encoder *encoder)
+{
+ struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+ struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+
+ zx_writel(tvenc->mmio + VENC_ENABLE, 0);
+
+ vou_inf_disable(VOU_TV_ENC, encoder->crtc);
+
+ /* Clear bit to power down TVENC DAC */
+ regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0);
+}
+
+static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs = {
+ .enable = zx_tvenc_encoder_enable,
+ .disable = zx_tvenc_encoder_disable,
+ .mode_set = zx_tvenc_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int zx_tvenc_connector_get_modes(struct drm_connector *connector)
+{
+ struct zx_tvenc *tvenc = to_zx_tvenc(connector);
+ struct device *dev = tvenc->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
+ const struct zx_tvenc_mode *zmode = tvenc_modes[i];
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, &zmode->mode);
+ if (!mode) {
+ DRM_DEV_ERROR(dev, "failed to duplicate drm mode\n");
+ continue;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ return i;
+}
+
+static enum drm_mode_status
+zx_tvenc_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct zx_tvenc *tvenc = to_zx_tvenc(connector);
+ const struct zx_tvenc_mode *zmode;
+
+ zmode = zx_tvenc_find_zmode(mode);
+ if (!zmode) {
+ DRM_DEV_ERROR(tvenc->dev, "unsupported mode: %s\n", mode->name);
+ return MODE_NOMODE;
+ }
+
+ return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs = {
+ .get_modes = zx_tvenc_connector_get_modes,
+ .mode_valid = zx_tvenc_connector_mode_valid,
+};
+
+static const struct drm_connector_funcs zx_tvenc_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc)
+{
+ struct drm_encoder *encoder = &tvenc->encoder;
+ struct drm_connector *connector = &tvenc->connector;
+
+ /*
+ * The tvenc is designed to use aux channel, as there is a deflicker
+ * block for the channel.
+ */
+ encoder->possible_crtcs = BIT(1);
+
+ drm_encoder_init(drm, encoder, &zx_tvenc_encoder_funcs,
+ DRM_MODE_ENCODER_TVDAC, NULL);
+ drm_encoder_helper_add(encoder, &zx_tvenc_encoder_helper_funcs);
+
+ connector->interlace_allowed = true;
+
+ drm_connector_init(drm, connector, &zx_tvenc_connector_funcs,
+ DRM_MODE_CONNECTOR_Composite);
+ drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ return 0;
+}
+
+static int zx_tvenc_pwrctrl_init(struct zx_tvenc *tvenc)
+{
+ struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+ struct device *dev = tvenc->dev;
+ struct of_phandle_args out_args;
+ struct regmap *regmap;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(dev->of_node,
+ "zte,tvenc-power-control", 2, 0, &out_args);
+ if (ret)
+ return ret;
+
+ regmap = syscon_node_to_regmap(out_args.np);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ goto out;
+ }
+
+ pwrctrl->regmap = regmap;
+ pwrctrl->reg = out_args.args[0];
+ pwrctrl->mask = out_args.args[1];
+
+out:
+ of_node_put(out_args.np);
+ return ret;
+}
+
+static int zx_tvenc_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct resource *res;
+ struct zx_tvenc *tvenc;
+ int ret;
+
+ tvenc = devm_kzalloc(dev, sizeof(*tvenc), GFP_KERNEL);
+ if (!tvenc)
+ return -ENOMEM;
+
+ tvenc->dev = dev;
+ dev_set_drvdata(dev, tvenc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ tvenc->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(tvenc->mmio)) {
+ ret = PTR_ERR(tvenc->mmio);
+ DRM_DEV_ERROR(dev, "failed to remap tvenc region: %d\n", ret);
+ return ret;
+ }
+
+ ret = zx_tvenc_pwrctrl_init(tvenc);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret);
+ return ret;
+ }
+
+ ret = zx_tvenc_register(drm, tvenc);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register tvenc: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void zx_tvenc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ /* Nothing to do */
+}
+
+static const struct component_ops zx_tvenc_component_ops = {
+ .bind = zx_tvenc_bind,
+ .unbind = zx_tvenc_unbind,
+};
+
+static int zx_tvenc_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &zx_tvenc_component_ops);
+}
+
+static int zx_tvenc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &zx_tvenc_component_ops);
+ return 0;
+}
+
+static const struct of_device_id zx_tvenc_of_match[] = {
+ { .compatible = "zte,zx296718-tvenc", },
+ { /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_tvenc_of_match);
+
+struct platform_driver zx_tvenc_driver = {
+ .probe = zx_tvenc_probe,
+ .remove = zx_tvenc_remove,
+ .driver = {
+ .name = "zx-tvenc",
+ .of_match_table = zx_tvenc_of_match,
+ },
+};
diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h
new file mode 100644
index 000000000000..bd91f5dcc1f3
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Linaro Ltd.
+ * Copyright 2017 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ZX_TVENC_REGS_H__
+#define __ZX_TVENC_REGS_H__
+
+#define VENC_VIDEO_INFO 0x04
+#define VENC_VIDEO_RES 0x08
+#define VENC_FIELD1_PARAM 0x10
+#define VENC_FIELD2_PARAM 0x14
+#define VENC_LINE_O_1 0x18
+#define VENC_LINE_E_1 0x1c
+#define VENC_LINE_O_2 0x20
+#define VENC_LINE_E_2 0x24
+#define VENC_LINE_TIMING_PARAM 0x28
+#define VENC_WEIGHT_VALUE 0x2c
+#define VENC_BLANK_BLACK_LEVEL 0x30
+#define VENC_BURST_LEVEL 0x34
+#define VENC_CONTROL_PARAM 0x3c
+#define VENC_SUB_CARRIER_PHASE1 0x40
+#define VENC_PHASE_LINE_INCR_CVBS 0x48
+#define VENC_ENABLE 0xa8
+
+#endif /* __ZX_TVENC_REGS_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index a86e3a5852a2..cf92d675feaa 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -40,6 +40,7 @@ struct zx_crtc_regs {
u32 fir_active;
u32 fir_htiming;
u32 fir_vtiming;
+ u32 sec_vtiming;
u32 timing_shift;
u32 timing_pi_shift;
};
@@ -48,6 +49,7 @@ static const struct zx_crtc_regs main_crtc_regs = {
.fir_active = FIR_MAIN_ACTIVE,
.fir_htiming = FIR_MAIN_H_TIMING,
.fir_vtiming = FIR_MAIN_V_TIMING,
+ .sec_vtiming = SEC_MAIN_V_TIMING,
.timing_shift = TIMING_MAIN_SHIFT,
.timing_pi_shift = TIMING_MAIN_PI_SHIFT,
};
@@ -56,6 +58,7 @@ static const struct zx_crtc_regs aux_crtc_regs = {
.fir_active = FIR_AUX_ACTIVE,
.fir_htiming = FIR_AUX_H_TIMING,
.fir_vtiming = FIR_AUX_V_TIMING,
+ .sec_vtiming = SEC_AUX_V_TIMING,
.timing_shift = TIMING_AUX_SHIFT,
.timing_pi_shift = TIMING_AUX_PI_SHIFT,
};
@@ -65,7 +68,17 @@ struct zx_crtc_bits {
u32 polarity_shift;
u32 int_frame_mask;
u32 tc_enable;
- u32 gl_enable;
+ u32 sec_vactive_shift;
+ u32 sec_vactive_mask;
+ u32 interlace_select;
+ u32 pi_enable;
+ u32 div_vga_shift;
+ u32 div_pic_shift;
+ u32 div_tvenc_shift;
+ u32 div_hdmi_pnx_shift;
+ u32 div_hdmi_shift;
+ u32 div_inf_shift;
+ u32 div_layer_shift;
};
static const struct zx_crtc_bits main_crtc_bits = {
@@ -73,7 +86,17 @@ static const struct zx_crtc_bits main_crtc_bits = {
.polarity_shift = MAIN_POL_SHIFT,
.int_frame_mask = TIMING_INT_MAIN_FRAME,
.tc_enable = MAIN_TC_EN,
- .gl_enable = OSD_CTRL0_GL0_EN,
+ .sec_vactive_shift = SEC_VACT_MAIN_SHIFT,
+ .sec_vactive_mask = SEC_VACT_MAIN_MASK,
+ .interlace_select = MAIN_INTERLACE_SEL,
+ .pi_enable = MAIN_PI_EN,
+ .div_vga_shift = VGA_MAIN_DIV_SHIFT,
+ .div_pic_shift = PIC_MAIN_DIV_SHIFT,
+ .div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
+ .div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
+ .div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
+ .div_inf_shift = INF_MAIN_DIV_SHIFT,
+ .div_layer_shift = LAYER_MAIN_DIV_SHIFT,
};
static const struct zx_crtc_bits aux_crtc_bits = {
@@ -81,7 +104,17 @@ static const struct zx_crtc_bits aux_crtc_bits = {
.polarity_shift = AUX_POL_SHIFT,
.int_frame_mask = TIMING_INT_AUX_FRAME,
.tc_enable = AUX_TC_EN,
- .gl_enable = OSD_CTRL0_GL1_EN,
+ .sec_vactive_shift = SEC_VACT_AUX_SHIFT,
+ .sec_vactive_mask = SEC_VACT_AUX_MASK,
+ .interlace_select = AUX_INTERLACE_SEL,
+ .pi_enable = AUX_PI_EN,
+ .div_vga_shift = VGA_AUX_DIV_SHIFT,
+ .div_pic_shift = PIC_AUX_DIV_SHIFT,
+ .div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
+ .div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
+ .div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
+ .div_inf_shift = INF_AUX_DIV_SHIFT,
+ .div_layer_shift = LAYER_AUX_DIV_SHIFT,
};
struct zx_crtc {
@@ -97,6 +130,40 @@ struct zx_crtc {
#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
+struct vou_layer_bits {
+ u32 enable;
+ u32 chnsel;
+ u32 clksel;
+};
+
+static const struct vou_layer_bits zx_gl_bits[GL_NUM] = {
+ {
+ .enable = OSD_CTRL0_GL0_EN,
+ .chnsel = OSD_CTRL0_GL0_SEL,
+ .clksel = VOU_CLK_GL0_SEL,
+ }, {
+ .enable = OSD_CTRL0_GL1_EN,
+ .chnsel = OSD_CTRL0_GL1_SEL,
+ .clksel = VOU_CLK_GL1_SEL,
+ },
+};
+
+static const struct vou_layer_bits zx_vl_bits[VL_NUM] = {
+ {
+ .enable = OSD_CTRL0_VL0_EN,
+ .chnsel = OSD_CTRL0_VL0_SEL,
+ .clksel = VOU_CLK_VL0_SEL,
+ }, {
+ .enable = OSD_CTRL0_VL1_EN,
+ .chnsel = OSD_CTRL0_VL1_SEL,
+ .clksel = VOU_CLK_VL1_SEL,
+ }, {
+ .enable = OSD_CTRL0_VL2_EN,
+ .chnsel = OSD_CTRL0_VL2_SEL,
+ .clksel = VOU_CLK_VL2_SEL,
+ },
+};
+
struct zx_vou_hw {
struct device *dev;
void __iomem *osd;
@@ -112,6 +179,33 @@ struct zx_vou_hw {
struct zx_crtc *aux_crtc;
};
+enum vou_inf_data_sel {
+ VOU_YUV444 = 0,
+ VOU_RGB_101010 = 1,
+ VOU_RGB_888 = 2,
+ VOU_RGB_666 = 3,
+};
+
+struct vou_inf {
+ enum vou_inf_id id;
+ enum vou_inf_data_sel data_sel;
+ u32 clocks_en_bits;
+ u32 clocks_sel_bits;
+};
+
+static struct vou_inf vou_infs[] = {
+ [VOU_HDMI] = {
+ .data_sel = VOU_YUV444,
+ .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
+ .clocks_sel_bits = BIT(13) | BIT(2),
+ },
+ [VOU_TV_ENC] = {
+ .data_sel = VOU_YUV444,
+ .clocks_en_bits = BIT(15),
+ .clocks_sel_bits = BIT(11) | BIT(0),
+ },
+};
+
static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
{
struct zx_crtc *zcrtc = to_zx_crtc(crtc);
@@ -119,20 +213,30 @@ static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
return zcrtc->vou;
}
-void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
+void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
+ enum vou_inf_hdmi_audio aud)
{
struct zx_crtc *zcrtc = to_zx_crtc(crtc);
struct zx_vou_hw *vou = zcrtc->vou;
+
+ zx_writel_mask(vou->vouctl + VOU_INF_HDMI_CTRL, VOU_HDMI_AUD_MASK, aud);
+}
+
+void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+ struct zx_vou_hw *vou = zcrtc->vou;
+ struct vou_inf *inf = &vou_infs[id];
bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
- u32 data_sel_shift = inf->id << 1;
+ u32 data_sel_shift = id << 1;
/* Select data format */
zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
inf->data_sel << data_sel_shift);
/* Select channel */
- zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id,
- zcrtc->chn_type << inf->id);
+ zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id,
+ zcrtc->chn_type << id);
/* Select interface clocks */
zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
@@ -143,20 +247,79 @@ void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
inf->clocks_en_bits);
/* Enable the device */
- zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id);
+ zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id);
}
-void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc)
+void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
{
struct zx_vou_hw *vou = crtc_to_vou(crtc);
+ struct vou_inf *inf = &vou_infs[id];
/* Disable the device */
- zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0);
+ zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0);
/* Disable interface clocks */
zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
}
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+ struct vou_div_config *configs, int num)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+ struct zx_vou_hw *vou = zcrtc->vou;
+ const struct zx_crtc_bits *bits = zcrtc->bits;
+ int i;
+
+ /* Clear update flag bit */
+ zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
+
+ for (i = 0; i < num; i++) {
+ struct vou_div_config *cfg = configs + i;
+ u32 reg, shift;
+
+ switch (cfg->id) {
+ case VOU_DIV_VGA:
+ reg = VOU_CLK_SEL;
+ shift = bits->div_vga_shift;
+ break;
+ case VOU_DIV_PIC:
+ reg = VOU_CLK_SEL;
+ shift = bits->div_pic_shift;
+ break;
+ case VOU_DIV_TVENC:
+ reg = VOU_DIV_PARA;
+ shift = bits->div_tvenc_shift;
+ break;
+ case VOU_DIV_HDMI_PNX:
+ reg = VOU_DIV_PARA;
+ shift = bits->div_hdmi_pnx_shift;
+ break;
+ case VOU_DIV_HDMI:
+ reg = VOU_DIV_PARA;
+ shift = bits->div_hdmi_shift;
+ break;
+ case VOU_DIV_INF:
+ reg = VOU_DIV_PARA;
+ shift = bits->div_inf_shift;
+ break;
+ case VOU_DIV_LAYER:
+ reg = VOU_DIV_PARA;
+ shift = bits->div_layer_shift;
+ break;
+ default:
+ continue;
+ }
+
+ /* Each divider occupies 3 bits */
+ zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
+ cfg->val << shift);
+ }
+
+ /* Set update flag bit to get dividers effected */
+ zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
+ DIV_PARA_UPDATE);
+}
+
static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
{
zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
@@ -165,11 +328,13 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
static void zx_crtc_enable(struct drm_crtc *crtc)
{
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
struct zx_crtc *zcrtc = to_zx_crtc(crtc);
struct zx_vou_hw *vou = zcrtc->vou;
const struct zx_crtc_regs *regs = zcrtc->regs;
const struct zx_crtc_bits *bits = zcrtc->bits;
struct videomode vm;
+ u32 scan_mask;
u32 pol = 0;
u32 val;
int ret;
@@ -177,7 +342,7 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
drm_display_mode_to_videomode(mode, &vm);
/* Set up timing parameters */
- val = V_ACTIVE(vm.vactive - 1);
+ val = V_ACTIVE((interlaced ? vm.vactive / 2 : vm.vactive) - 1);
val |= H_ACTIVE(vm.hactive - 1);
zx_writel(vou->timing + regs->fir_active, val);
@@ -191,6 +356,25 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
val |= FRONT_PORCH(vm.vfront_porch - 1);
zx_writel(vou->timing + regs->fir_vtiming, val);
+ if (interlaced) {
+ u32 shift = bits->sec_vactive_shift;
+ u32 mask = bits->sec_vactive_mask;
+
+ val = zx_readl(vou->timing + SEC_V_ACTIVE);
+ val &= ~mask;
+ val |= ((vm.vactive / 2 - 1) << shift) & mask;
+ zx_writel(vou->timing + SEC_V_ACTIVE, val);
+
+ val = SYNC_WIDE(vm.vsync_len - 1);
+ /*
+ * The vback_porch for the second field needs to shift one on
+ * the value for the first field.
+ */
+ val |= BACK_PORCH(vm.vback_porch);
+ val |= FRONT_PORCH(vm.vfront_porch - 1);
+ zx_writel(vou->timing + regs->sec_vtiming, val);
+ }
+
/* Set up polarities */
if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
pol |= 1 << POL_VSYNC_SHIFT;
@@ -201,9 +385,17 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
pol << bits->polarity_shift);
/* Setup SHIFT register by following what ZTE BSP does */
- zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL);
+ val = H_SHIFT_VAL;
+ if (interlaced)
+ val |= V_SHIFT_VAL << 16;
+ zx_writel(vou->timing + regs->timing_shift, val);
zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
+ /* Progressive or interlace scan select */
+ scan_mask = bits->interlace_select | bits->pi_enable;
+ zx_writel_mask(vou->timing + SCAN_CTRL, scan_mask,
+ interlaced ? scan_mask : 0);
+
/* Enable TIMING_CTRL */
zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
bits->tc_enable);
@@ -214,16 +406,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
vm.vactive << CHN_SCREEN_H_SHIFT);
+ /* Configure channel interlace buffer control */
+ zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
+ interlaced ? CHN_INTERLACE_EN : 0);
+
/* Update channel */
vou_chn_set_update(zcrtc);
/* Enable channel */
zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE);
- /* Enable Graphic Layer */
- zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable,
- bits->gl_enable);
-
drm_crtc_vblank_on(crtc);
ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
@@ -247,9 +439,6 @@ static void zx_crtc_disable(struct drm_crtc *crtc)
drm_crtc_vblank_off(crtc);
- /* Disable Graphic Layer */
- zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0);
-
/* Disable channel */
zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0);
@@ -294,7 +483,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
enum vou_chn_type chn_type)
{
struct device *dev = vou->dev;
- struct zx_layer_data data;
+ struct zx_plane *zplane;
struct zx_crtc *zcrtc;
int ret;
@@ -305,19 +494,27 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
zcrtc->vou = vou;
zcrtc->chn_type = chn_type;
+ zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
+ if (!zplane)
+ return -ENOMEM;
+
+ zplane->dev = dev;
+
if (chn_type == VOU_CHN_MAIN) {
- data.layer = vou->osd + MAIN_GL_OFFSET;
- data.csc = vou->osd + MAIN_CSC_OFFSET;
- data.hbsc = vou->osd + MAIN_HBSC_OFFSET;
- data.rsz = vou->otfppu + MAIN_RSZ_OFFSET;
+ zplane->layer = vou->osd + MAIN_GL_OFFSET;
+ zplane->csc = vou->osd + MAIN_CSC_OFFSET;
+ zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET;
+ zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET;
+ zplane->bits = &zx_gl_bits[0];
zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
zcrtc->regs = &main_crtc_regs;
zcrtc->bits = &main_crtc_bits;
} else {
- data.layer = vou->osd + AUX_GL_OFFSET;
- data.csc = vou->osd + AUX_CSC_OFFSET;
- data.hbsc = vou->osd + AUX_HBSC_OFFSET;
- data.rsz = vou->otfppu + AUX_RSZ_OFFSET;
+ zplane->layer = vou->osd + AUX_GL_OFFSET;
+ zplane->csc = vou->osd + AUX_CSC_OFFSET;
+ zplane->hbsc = vou->osd + AUX_HBSC_OFFSET;
+ zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET;
+ zplane->bits = &zx_gl_bits[1];
zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
zcrtc->regs = &aux_crtc_regs;
zcrtc->bits = &aux_crtc_bits;
@@ -331,13 +528,14 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
return ret;
}
- zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY);
- if (IS_ERR(zcrtc->primary)) {
- ret = PTR_ERR(zcrtc->primary);
+ ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY);
+ if (ret) {
DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret);
return ret;
}
+ zcrtc->primary = &zplane->plane;
+
ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
&zx_crtc_funcs, NULL);
if (ret) {
@@ -393,6 +591,78 @@ void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe)
zcrtc->bits->int_frame_mask, 0);
}
+void zx_vou_layer_enable(struct drm_plane *plane)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc);
+ struct zx_vou_hw *vou = zcrtc->vou;
+ struct zx_plane *zplane = to_zx_plane(plane);
+ const struct vou_layer_bits *bits = zplane->bits;
+
+ if (zcrtc->chn_type == VOU_CHN_MAIN) {
+ zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0);
+ zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0);
+ } else {
+ zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel,
+ bits->chnsel);
+ zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel,
+ bits->clksel);
+ }
+
+ zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
+}
+
+void zx_vou_layer_disable(struct drm_plane *plane)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc);
+ struct zx_vou_hw *vou = zcrtc->vou;
+ struct zx_plane *zplane = to_zx_plane(plane);
+ const struct vou_layer_bits *bits = zplane->bits;
+
+ zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
+}
+
+static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou)
+{
+ struct device *dev = vou->dev;
+ struct zx_plane *zplane;
+ int i;
+ int ret;
+
+ /*
+ * VL0 has some quirks on scaling support which need special handling.
+ * Let's leave it out for now.
+ */
+ for (i = 1; i < VL_NUM; i++) {
+ zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
+ if (!zplane) {
+ DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i);
+ return;
+ }
+
+ zplane->layer = vou->osd + OSD_VL_OFFSET(i);
+ zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i);
+ zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i);
+ zplane->bits = &zx_vl_bits[i];
+
+ ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i);
+ continue;
+ }
+ }
+}
+
+static inline void zx_osd_int_update(struct zx_crtc *zcrtc)
+{
+ struct drm_crtc *crtc = &zcrtc->crtc;
+ struct drm_plane *plane;
+
+ vou_chn_set_update(zcrtc);
+
+ drm_for_each_plane_mask(plane, crtc->dev, crtc->state->plane_mask)
+ zx_plane_set_update(plane);
+}
+
static irqreturn_t vou_irq_handler(int irq, void *dev_id)
{
struct zx_vou_hw *vou = dev_id;
@@ -412,15 +682,11 @@ static irqreturn_t vou_irq_handler(int irq, void *dev_id)
state = zx_readl(vou->osd + OSD_INT_STA);
zx_writel(vou->osd + OSD_INT_CLRSTA, state);
- if (state & OSD_INT_MAIN_UPT) {
- vou_chn_set_update(vou->main_crtc);
- zx_plane_set_update(vou->main_crtc->primary);
- }
+ if (state & OSD_INT_MAIN_UPT)
+ zx_osd_int_update(vou->main_crtc);
- if (state & OSD_INT_AUX_UPT) {
- vou_chn_set_update(vou->aux_crtc);
- zx_plane_set_update(vou->aux_crtc->primary);
- }
+ if (state & OSD_INT_AUX_UPT)
+ zx_osd_int_update(vou->aux_crtc);
if (state & OSD_INT_ERROR)
DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state);
@@ -451,19 +717,9 @@ static void vou_dtrc_init(struct zx_vou_hw *vou)
static void vou_hw_init(struct zx_vou_hw *vou)
{
- /* Set GL0 to main channel and GL1 to aux channel */
- zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL0_SEL, 0);
- zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL1_SEL,
- OSD_CTRL0_GL1_SEL);
-
/* Release reset for all VOU modules */
zx_writel(vou->vouctl + VOU_SOFT_RST, ~0);
- /* Select main clock for GL0 and aux clock for GL1 module */
- zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL0_SEL, 0);
- zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL1_SEL,
- VOU_CLK_GL1_SEL);
-
/* Enable clock auto-gating for all VOU modules */
zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0);
@@ -600,6 +856,8 @@ static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
goto disable_ppu_clk;
}
+ zx_overlay_init(drm, vou);
+
return 0;
disable_ppu_clk:
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index 349e06cd86f4..57e3c31ee6a5 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -23,24 +23,48 @@ enum vou_inf_id {
VOU_VGA = 5,
};
-enum vou_inf_data_sel {
- VOU_YUV444 = 0,
- VOU_RGB_101010 = 1,
- VOU_RGB_888 = 2,
- VOU_RGB_666 = 3,
+enum vou_inf_hdmi_audio {
+ VOU_HDMI_AUD_SPDIF = BIT(0),
+ VOU_HDMI_AUD_I2S = BIT(1),
+ VOU_HDMI_AUD_DSD = BIT(2),
+ VOU_HDMI_AUD_HBR = BIT(3),
+ VOU_HDMI_AUD_PARALLEL = BIT(4),
};
-struct vou_inf {
- enum vou_inf_id id;
- enum vou_inf_data_sel data_sel;
- u32 clocks_en_bits;
- u32 clocks_sel_bits;
+void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
+ enum vou_inf_hdmi_audio aud);
+void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
+void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
+
+enum vou_div_id {
+ VOU_DIV_VGA,
+ VOU_DIV_PIC,
+ VOU_DIV_TVENC,
+ VOU_DIV_HDMI_PNX,
+ VOU_DIV_HDMI,
+ VOU_DIV_INF,
+ VOU_DIV_LAYER,
+};
+
+enum vou_div_val {
+ VOU_DIV_1 = 0,
+ VOU_DIV_2 = 1,
+ VOU_DIV_4 = 3,
+ VOU_DIV_8 = 7,
};
-void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc);
-void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc);
+struct vou_div_config {
+ enum vou_div_id id;
+ enum vou_div_val val;
+};
+
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+ struct vou_div_config *configs, int num);
int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
+void zx_vou_layer_enable(struct drm_plane *plane);
+void zx_vou_layer_disable(struct drm_plane *plane);
+
#endif /* __ZX_VOU_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
index f44e7a4ae441..c066ef123434 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -22,6 +22,15 @@
#define AUX_HBSC_OFFSET 0x860
#define AUX_RSZ_OFFSET 0x800
+#define OSD_VL0_OFFSET 0x040
+#define OSD_VL_OFFSET(i) (OSD_VL0_OFFSET + 0x050 * (i))
+
+#define HBSC_VL0_OFFSET 0x760
+#define HBSC_VL_OFFSET(i) (HBSC_VL0_OFFSET + 0x040 * (i))
+
+#define RSZ_VL1_U0 0xa00
+#define RSZ_VL_OFFSET(i) (RSZ_VL1_U0 + 0x200 * (i))
+
/* OSD (GPC_GLOBAL) registers */
#define OSD_INT_STA 0x04
#define OSD_INT_CLRSTA 0x08
@@ -42,6 +51,12 @@
)
#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
#define OSD_CTRL0 0x10
+#define OSD_CTRL0_VL0_EN BIT(13)
+#define OSD_CTRL0_VL0_SEL BIT(12)
+#define OSD_CTRL0_VL1_EN BIT(11)
+#define OSD_CTRL0_VL1_SEL BIT(10)
+#define OSD_CTRL0_VL2_EN BIT(9)
+#define OSD_CTRL0_VL2_SEL BIT(8)
#define OSD_CTRL0_GL0_EN BIT(7)
#define OSD_CTRL0_GL0_SEL BIT(6)
#define OSD_CTRL0_GL1_EN BIT(5)
@@ -60,6 +75,8 @@
#define CHN_SCREEN_H_SHIFT 5
#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT)
#define CHN_UPDATE 0x08
+#define CHN_INTERLACE_BUF_CTRL 0x24
+#define CHN_INTERLACE_EN BIT(2)
/* TIMING_CTRL registers */
#define TIMING_TC_ENABLE 0x04
@@ -102,6 +119,19 @@
#define TIMING_MAIN_SHIFT 0x2c
#define TIMING_AUX_SHIFT 0x30
#define H_SHIFT_VAL 0x0048
+#define V_SHIFT_VAL 0x0001
+#define SCAN_CTRL 0x34
+#define AUX_PI_EN BIT(19)
+#define MAIN_PI_EN BIT(18)
+#define AUX_INTERLACE_SEL BIT(1)
+#define MAIN_INTERLACE_SEL BIT(0)
+#define SEC_V_ACTIVE 0x38
+#define SEC_VACT_MAIN_SHIFT 0
+#define SEC_VACT_MAIN_MASK (0xffff << SEC_VACT_MAIN_SHIFT)
+#define SEC_VACT_AUX_SHIFT 16
+#define SEC_VACT_AUX_MASK (0xffff << SEC_VACT_AUX_SHIFT)
+#define SEC_MAIN_V_TIMING 0x3c
+#define SEC_AUX_V_TIMING 0x40
#define TIMING_MAIN_PI_SHIFT 0x68
#define TIMING_AUX_PI_SHIFT 0x6c
#define H_PI_SHIFT_VAL 0x000f
@@ -146,10 +176,31 @@
#define VOU_INF_DATA_SEL 0x08
#define VOU_SOFT_RST 0x14
#define VOU_CLK_SEL 0x18
+#define VGA_AUX_DIV_SHIFT 29
+#define VGA_MAIN_DIV_SHIFT 26
+#define PIC_MAIN_DIV_SHIFT 23
+#define PIC_AUX_DIV_SHIFT 20
+#define VOU_CLK_VL2_SEL BIT(8)
+#define VOU_CLK_VL1_SEL BIT(7)
+#define VOU_CLK_VL0_SEL BIT(6)
#define VOU_CLK_GL1_SEL BIT(5)
#define VOU_CLK_GL0_SEL BIT(4)
+#define VOU_DIV_PARA 0x1c
+#define DIV_PARA_UPDATE BIT(31)
+#define TVENC_AUX_DIV_SHIFT 28
+#define HDMI_AUX_PNX_DIV_SHIFT 25
+#define HDMI_MAIN_PNX_DIV_SHIFT 22
+#define HDMI_AUX_DIV_SHIFT 19
+#define HDMI_MAIN_DIV_SHIFT 16
+#define TVENC_MAIN_DIV_SHIFT 13
+#define INF_AUX_DIV_SHIFT 9
+#define INF_MAIN_DIV_SHIFT 6
+#define LAYER_AUX_DIV_SHIFT 3
+#define LAYER_MAIN_DIV_SHIFT 0
#define VOU_CLK_REQEN 0x20
#define VOU_CLK_EN 0x24
+#define VOU_INF_HDMI_CTRL 0x30
+#define VOU_HDMI_AUD_MASK 0x1f
/* OTFPPU_CTRL registers */
#define OTFPPU_RSZ_DATA_SOURCE 0x04